WebDriver/Marionette/JSON Protocol

From MozillaWiki
Jump to navigation Jump to search

The Marionette JSON Protocol is mapped to the Selenium JSON Wire Protocol, although additional commands will be added. For existing commands, the meaning of the commands should remain unchanged, including types of parameters and return values. Some of these details are only available in the existing Firefox WebDriver implementation (e.g., the return value of /status).

The return values shown are those that will be returned from the Marionette service; the Marionette actor in the remote debugger will add { "from": "marionette" } to these values as per remote debugger convention.

Error handling

The response for any error will be in the following format:

{
    'error': {
        'status': status_code,
        'message': optional_error_message,
        'stacktrace': optional_stack_trace
    }
}

The error codes shall be one of the response codes described here, or 500 for a generic error.

Marionette JSON protocol

Wire Protocol Command Marionette JSON Description Return Value
GET /status
{ 
    "to": "marionette",
    "command": "getStatus"
}
Query the server's current status.


References: nsCommandProcessor.js:getStatus

{
    "value": {
        "os": {
            "arch": nsIXULRuntime.XPCOMABI||"unknown",
            "name": nsIXULRuntime.OS,
            "version": "unknown"
        },
        "build": {
            "revision": "unknown",
            "time": "unknown",
            "version": "unknown"
        }
    }
}

The 'unknown' values are from the current Firefox WebDriver implementation; we can supply some of these if we want.

POST /session
{
    "to": "marionette",
    "command": "newSession"
}
Create a new session, and returns the new session's id.


References: nsCommandProcessor.js:newSession, sessionstore.js:createSession

{
    "value": nsIUUIDGenerator.generateUUID().toString().substring(1, length - 1)
}
GET /session/:sessionId
{
    "to": "marionette",
    "command": "getSessionCapabilities",
    "session": sessionId
}
Returns the session capabilities for the specified session.


References: nsCommandProcessor.js:getSessionCapabilities

{   
    "value":
    {
        "cssSelectorsEnabled": true,
        "browserName": "firefox", // may want some other value for B2G
        "handlesAlerts": true,
        "javascriptEnabled": true,
        "nativeEvents": true, // ??
        "platform": nsIXULRuntime.OS,
        "takeScreenshot": true, // not sure if we will support this
        "version": nsIXULAppInfo.version
    }
}
DELETE /session/:sessionId
{
    "to": "marionette",
    "command": "deleteSession",
    "session": sessionId
}
Terminates the existing session and performs any necessary cleanup.


References: nsCommandProcessor:deleteSession

{
    "ok": true
}
POST /session/:sessionId/timeouts/async_script
{
    "to": "marionette",
    "session": sessionId,
    "command": "setScriptTimeout",
    "value": value_in_ms
}
Set the amount of time, in milliseconds, that asynchronous scripts executed by 'execute_async' are permitted to run before they are aborted and a Timeout error is returned to the client.


References: firefoxDriver:setScriptTimeout

{
    "ok": true
}
POST /session/:sessionId/timeouts/implicit_wait
{
    "to": "marionette",
    "session": sessionId,
    "command": "setSearchTimeout",
    "value": value_in_ms
}
Set the amount of time the driver should wait when searching for elements. When searching for a single element, the driver should poll the page until an element is found or the timeout expires, whichever occurs first. When searching for multiple elements, the driver should poll the page until at least one element is found or the timeout expires, at which point it should return an empty list. If this command is never sent, the driver should default to an implicit wait of 0ms.


References: firefoxDriver.js:implicitlyWait

{
    "ok": true
}
GET /session/:sessionId/window_handle
{
    "to": "marionette",
    "session": sessionId,
    "command": "getWindow"
}
Retrieve the current window handle.


References: firefoxDriver:getCurrentWindowHandle, firefoxDriver.js:__defineGetter__("id"), webdriverserver.js:getNextId

{
    "value": window_id
}

Note the current webdriver implementation uses a random GUID for the window_id of the window that the fxdriver is loaded in, and uses window.content.name for the window_id of other windows. We may want to use a different mechanism.

GET /session/:sessionId/window_handles
{
    "to": "marionette",
    "session": sessionId,
    "command": "getWindows"
}
Retrieve the list of all window handles available to the session.


References: nsCommandProcessor.js:getWindowHandles

{
    "value": [window_id_1, window_id_2, ...]
}

Note the current webdriver implementation uses a random GUID for the window_id of the window that the fxdriver is loaded in, and uses window.content.name for the window_id of other windows. We may want to use a different mechanism.

GET /session/:sessionId/url
{
    "to": "marionette",
    "session": sessionId,
    "command": "getUrl"
}
Retrieve the URL of the current page.


References: firefoxDriver.js:getCurrentUrl

{
    "value": url
}
POST /session/:sessionId/url
{
    "to": "marionette",
    "session": sessionId,
    "command": "goUrl",
    "value": url
}
Navigate to a new URL.


References: firefoxDriver.js:get

{
    "ok": true
}
POST /session/:sessionId/forward
{
    "to": "marionette",
    "session": sessionId,
    "command": "goForward"
}
Navigate forwards in the browser history, if possible.


References: firefoxDriver.js:goForward

{
    "ok": true
}
POST /session/:sessionId/back
{
    "to": "marionette",
    "session": sessionId,
    "command": "goBack"
}
Navigate backwards in the browser history, if possible.


References: firefoxDriver.js:goBack

{
    "ok": true
}
POST /session/:sessionId/refresh
{
    "to": "marionette",
    "session": sessionId,
    "command": "refresh"
}
Refresh the current page.


References: firefoxDriver.js:refresh

{
    "ok": true
}
POST /session/:sessionId/execute
{
    "to": "marionette",
    "session": sessionId,
    "command": "executeScript",
    "value": script_to_execute,
    "args": [arg1, arg2, ...],
    "newSandbox: boolean value,
}
Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame. The executed script is assumed to be synchronous and the result of evaluating the script is returned to the client. If newSandbox is set to false, then we will preserve the context from a previous execute call, so you can share globals.


The script argument defines the script to execute in the form of a function body. The value returned by that function will be returned to the client. The function will be invoked with the provided args array and the values may be accessed via the arguments object in the order specified.

For example, if

'args' = ['testing']

the script_to_execute might be:

return 'the first argument is ' + arguments[0];

References: firefoxDriver.js:injectAndExecuteScript, evaluate.js

{
    "value": script_result
}
POST /session/:sessionId/execute_async
{
    "to": "marionette",
    "session": sessionId,
    "command": "executeAsyncScript",
    "value": script_to_execute,
    "args": [arg1, arg2, ...],
    "newSandbox": boolean value,
}
Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame. The executed script is assumed to be asynchronous and must signal that is done by invoking the provided callback, which is always provided as the final argument to the function. The value to this callback will be returned to the client. If newSandbox is set to false, then we will preserve the context from a previous execute call, so you can share globals.


Asynchronous script commands may not span page loads. If an unload event is fired while waiting for a script result, an error should be returned to the client. XXX: not sure if we want this to be true or not.

The script argument defines the script to execute in the form of a function body. The function will be invoked with the provided args array and the values may be accessed via the arguments object in the order specified. The final argument will always be a callback function that must be invoked to signal that the script has finished.

For example, if

'args' = ['testing']

the script_to_execute might be:

var arg1 = arguments[0];
var callback = arguments[arguments.length - 1];
var count = 0;
window.setTimeout(function() {count += 1;}, 250);
window.setTimeout(function() {count += 2;}, 250);
window.setTimeout(function() {callback({firstArgument: arg1, count: count});}, 1000);

References: firefoxDriver.js:injectAndExecuteScript, evaluate.js

{
    "value": script_result
}
POST /session/:sessionId/frame
 {
    "to": "marionette",
    "session": sessionId,
    "command": "switchToFrame",
    "value": frame's id, name, index, or null
 }

or

 {
    "to": "marionette",
    "session": sessionId,
    "command": "switchToFrame",
    "element": frame element's uuid
 }
Switch to the specified frame. The frame can be specified using the frame's id, name, or index, or the frame's element uuid. If you specify null, switch to the default frame.


References: firefoxDriver.js:switchToFrame

{
    "ok": true
}
POST /session/:sessionId/window
{
    "to": "marionette",
    "session": sessionId,
    "command": "switchToWindow",
    "value": window_name
}
Change focus to another window. The window to change focus to may be specified by its server assigned window handle (from getWindows), or by the value of its name attribute.


References: nsCommandProcessor.js:switchToWindow

{
    "ok": true
}
DELETE /session/:sessionId/window
{
    "to": "marionette",
    "session": sessionId,
    "command": "closeWindow"
}
Closes the current window. XXX: we probably want to add an optional argument so that we can close any window, and not just the current one.


References: firefoxDriver.js:close

{
    "ok": true
}
POST /session/:sessionId/element
{
    "to": "marionette",
    "session": sessionId,
    "command": "findElement",
    "using": search_method,
    "value": search_target
}
Search for an element on the page, starting from the document root. The located element will be returned as a WebElement JSON object (basically, a UUID). See this table for the locator strategies that each server should support. Each locator must return the first matching element located in the DOM.


References: firefoxDriver.js:findElementInternal, utils.js:addToKnownElements

{
    "value": element_uuid
}

Note: the returned value is a uuid randomly assigned to the element by the server. The server maintains a map of uuid's to elements.

POST /session/:sessionId/elements
{
    "to": "marionette",
    "session": sessionId,
    "command": "findElements",
    "using": search_method,
    "value": search_target
}
Search for multiple elements on the page, starting from the document root. The located elements will be returned as WebElement JSON objects (an array UUID's). See this table for the locator strategies that each server should support. Elements should be returned in the order located in the DOM.
{
    "value": [element1_uuid, ...]
}
POST /session/:sessionId/element/:id/element
{
    "to": "marionette",
    "session": sessionId,
    "command": "findChildElement",
    "using": search_method,
    "element": parent_element_uuid,
    "value": search_target
}
Search for an element on the page, starting from the identified parent element. The located element will be returned as a WebElement JSON object (a UUID). See this table for the locator strategies that each server should support. Each locator must return the first matching element located in the DOM.
{
    "value": element_uuid
}

Note: the returned value is a uuid randomly assigned to the element by the server. The server maintains a map of uuid's to elements.

POST /session/:sessionId/element/:id/elements
{
    "to": "marionette",
    "session": sessionId,
    "command": "findChildElements",
    "using": search_method,
    "element": parent_element_uuid,
    "value": search_target
}
Search for multiple elements on the page, starting from the identified element. The located elements will be returned as WebElement JSON objects (an array of UUID's). See this table for the locator strategies that each server should support. Elements should be returned in the order located in the DOM.
{
    "value": [element1_uuid, ...]
}
POST /session/:sessionId/element/:id/click
{
    "to": "marionette",
    "session": sessionId,
    "command": "clickElement",
    "element": element_uuid
}
Click on an element.


Note: the current Selenium Firefox driver prefers to use native events for this, rather than DOM events. Do we want to do this also? Or should we use accessibles instead?

References: wrappedElement.js:clickElement

{
    "ok": true
}
GET /session/:sessionId/element/:id/text
{
    "to": "marionette",
    "session": sessionId,
    "command": "getElementText",
    "element": element_uuid
}
Returns the visible text for the element.


References: wrappedElement.js:getElementText

{
    "value": element_text
}
POST /session/:sessionId/element/:id/value
{
    "to": "marionette",
    "session": sessionId,
    "command": "sendKeysToElement",
    "element": element_uuid,
    "value": string
}
Send a sequence of key strokes to an element. Any UTF-8 character may be specified, however, if the server does not support native key events, it should simulate key strokes for a standard US keyboard layout. The Unicode Private Use Area code points, 0xE000-0xF8FF, are used to represent pressable, non-text keys. See table and notes here.


References: firefoxDriver.js:sendKeysToElement, utils.js:type

{
    "ok": true
}
GET /session/:sessionId/element/:id/value


(not documented, but present in the Firefox reference driver)

{
    "to": "marionette",
    "session": sessionId,
    "command": "getElementValue",
    "element": element_uuid
}
Returns the value of an element.


References: wrappedElement.js:getElementValue

{
    "value": element_value
}
POST /session/:sessionId/element/:id/clear
{
    "to": "marionette",
    "session": sessionId,
    "command": "clearElement",
    "element": element_uuid
}
Clear a TEXTAREA or text INPUT element's value.


References: wrappedElement.js:clearElement

{
   "ok": true
}
GET /session/:sessionId/element/:id/selected
{
    "to": "marionette",
    "session": sessionId,
    "command": "isElementSelected",
    "element": element_uuid
}
Determine if an OPTION element, or an INPUT element of type checkbox or radiobutton is currently selected.


References: wrappedElement.js:isElementSelected

{
    "value": boolean
}
GET /session/:sessionId/element/:id/equals/:other
{
    "to": "marionette",
    "session": sessionId,
    "command": "elementsEqual",
    "elements": [element1_uuid, element2_uuid]
}
Test if two element IDs refer to the same DOM element.


References: wrappedElement:elementEquals

{
    "value": boolean
}
GET /session/:sessionId/element/:id/enabled
{
    "to": "marionette",
    "session": sessionId,
    "command": "isElementEnabled",
    "element": element_uuid
}
Determine if an element is currently enabled.


References: wrappedElement.js:isElementEnabled, utils.js:isEnabled

{
    "value": boolean
}
GET /session/:sessionId/element/:id/displayed
{
    "to": "marionette",
    "session": sessionId,
    "command": "isElementDisplayed",
    "element": element_uuid
}
Determine if an element is currently displayed.


References: wrappedElement.js:isElementDisplayed, dom.js:isShown

{
    "value": boolean
}
GET /session/:sessionId/element/:id/attribute/:name
{
    "to": "marionette",
    "session": sessionId,
    "command": "getAttributeValue",
    "element": element_uuid,
    "name": attribute_name
}
Return the value of an element's attribute.


References: wrappedElement.js:getElementAttribute

{
    "value": attribute_value
}
none
{
    "to": "marionette",
    "session": sessionId,
    "command": "setContext",
    "value": "chrome" or "content"
}
Sets the execution context to "chrome" or "content" (the default). All commands issued after a context change will be implicitly targeted at the specified context.
{
    "ok": true
}
none
{
    "to": "marionette",
    "session": sessionId,
    "command": "log",
    "value": message,
    "level": level
}
Logs a message at the log level requested. If no log level is passed, "INFO" will be used.
{
    "ok": true
}
none
{
    "to": "marionette",
    "session": sessionId,
    "command": "getLogs"
}
Gets all logs recorded using the log method
{
    "value": [ ['INFO', 'asdf3', 'Fri Feb 10 2012 15:59:20 GMT-0500 (EST)'], ...
}