| Index: pkg/webdriver/webdriver.dart
|
| ===================================================================
|
| --- pkg/webdriver/webdriver.dart (revision 0)
|
| +++ pkg/webdriver/webdriver.dart (revision 0)
|
| @@ -0,0 +1,1360 @@
|
| +#library('webdriver');
|
| +#import('dart:json');
|
| +#import('dart:uri');
|
| +#import('dart:io');
|
| +#import('dart:math');
|
| +#source('base64decoder.dart');
|
| +
|
| +/**
|
| + * WebDriver bindings for Dart.
|
| + *
|
| + * These bindings are based on the WebDriver JSON wire protocol spec
|
| + * (http://code.google.com/p/selenium/wiki/JsonWireProtocol). Not
|
| + * all of these commands are implemented yet by WebDriver itself.
|
| + * Nontheless this is a complete implementation of the spec as the
|
| + * unsupported commands may be supported in the future. Currently,
|
| + * there are known issues with local and session storage, script
|
| + * execution, and log access.
|
| + *
|
| + * To use these bindings, the Selenium standalone server must be running.
|
| + * You can download it at http://code.google.com/p/selenium/downloads/list.
|
| + *
|
| + * There are a number of commands that use ids to access page elements.
|
| + * These ids are not the HTML ids; they are opaque ids internal to
|
| + * WebDriver. To get the id for an element you would first need to do
|
| + * a search, get the results, and extract the WebDriver id from the returned
|
| + * [Map] using the 'ELEMENT' key. For example:
|
| + *
|
| + * String id;
|
| + * WebDriverSession session;
|
| + * Future f = web_driver.newSession('chrome');
|
| + * f.chain((_session) {
|
| + * session = _session;
|
| + * return session.setUrl('http://my.web.site.com');
|
| + * }).chain((_) {
|
| + * return session.findElement('id', 'username');
|
| + * }).chain((element) {
|
| + * id = element['ELEMENT'];
|
| + * return session.sendKeyStrokesToElement(id,
|
| + * [ 'j', 'o', 'e', ' ', 'u', 's', 'e', 'r' ]);
|
| + * }).chain((_) {
|
| + * return session.submit(id);
|
| + * }).chain((_) {
|
| + * return session.close();
|
| + * }).then((_) {
|
| + * session = null;
|
| + * });
|
| + */
|
| +
|
| +void writeStringToFile(String fileName, String contents) {
|
| + var file = new File(fileName);
|
| + var ostream = file.openOutputStream(FileMode.WRITE);
|
| + ostream.writeString(contents);
|
| + ostream.close();
|
| +}
|
| +
|
| +void writeBytesToFile(String fileName, List<int> contents) {
|
| + var file = new File(fileName);
|
| + var ostream = file.openOutputStream(FileMode.WRITE);
|
| + ostream.write(contents);
|
| + ostream.close();
|
| +}
|
| +
|
| +class WebDriverError {
|
| + static List _errorTypes = null;
|
| + static List _errorDetails = null;
|
| + int statusCode;
|
| + String type;
|
| + String message;
|
| + String details;
|
| + String results;
|
| +
|
| + WebDriverError(this.statusCode, this.message, [this.results = '']) {
|
| + /** These correspond to WebDrive exception types. */
|
| + if (_errorTypes == null) {
|
| + _errorTypes = [
|
| + null,
|
| + 'IndexOutOfBounds',
|
| + 'NoCollection',
|
| + 'NoString',
|
| + 'NoStringLength',
|
| + 'NoStringWrapper',
|
| + 'NoSuchDriver',
|
| + 'NoSuchElement',
|
| + 'NoSuchFrame',
|
| + 'UnknownCommand',
|
| + 'ObsoleteElement',
|
| + 'ElementNotDisplayed',
|
| + 'InvalidElementState',
|
| + 'Unhandled',
|
| + 'Expected',
|
| + 'ElementNotSelectable',
|
| + 'NoSuchDocument',
|
| + 'UnexpectedJavascript',
|
| + 'NoScriptResult',
|
| + 'XPathLookup',
|
| + 'NoSuchCollection',
|
| + 'TimeOut',
|
| + 'NullPointer',
|
| + 'NoSuchWindow',
|
| + 'InvalidCookieDomain',
|
| + 'UnableToSetCookie',
|
| + 'UnexpectedAlertOpen',
|
| + 'NoAlertOpen',
|
| + 'ScriptTimeout',
|
| + 'InvalidElementCoordinates',
|
| + 'IMENotAvailable',
|
| + 'IMEEngineActivationFailed',
|
| + 'InvalidSelector',
|
| + 'SessionNotCreatedException',
|
| + 'MoveTargetOutOfBounds'
|
| + ];
|
| + // Explanations of the eror types. In thoses cases where the
|
| + // explanation is the same as the type (e.g. NoCollection), that is an
|
| + // error type used by an old version of the IE driver and is deprecated.
|
| + _errorDetails = [
|
| + null,
|
| + 'IndexOutOfBounds',
|
| + 'NoCollection',
|
| + 'NoString',
|
| + 'NoStringLength',
|
| + 'NoStringWrapper',
|
| + 'NoSuchDriver',
|
| + 'An element could not be located on the page using the given '
|
| + 'search parameters.',
|
| + 'A request to switch to a frame could not be satisfied because the '
|
| + 'frame could not be found.',
|
| + 'The requested resource could not be found, or a request was '
|
| + 'received using an HTTP method that is not supported by the '
|
| + 'mapped resource.',
|
| + 'An element command failed because the referenced element is no '
|
| + 'longer attached to the DOM.',
|
| + 'An element command could not be completed because the element '
|
| + 'is not visible on the page.',
|
| + 'An element command could not be completed because the element is in '
|
| + 'an invalid state (e.g. attempting to click a disabled element).',
|
| + 'An unknown server-side error occurred while processing the command.',
|
| + 'Expected',
|
| + 'An attempt was made to select an element that cannot be selected.',
|
| + 'NoSuchDocument',
|
| + 'An error occurred while executing user supplied JavaScript.',
|
| + 'NoScriptResult',
|
| + 'An error occurred while searching for an element by XPath.',
|
| + 'NoSuchCollection',
|
| + 'An operation did not complete before its timeout expired.',
|
| + 'NullPointer',
|
| + 'A request to switch to a different window could not be satisfied '
|
| + 'because the window could not be found.',
|
| + 'An illegal attempt was made to set a cookie under a different '
|
| + 'domain than the current page.',
|
| + 'A request to set a cookie\'s value could not be satisfied.',
|
| + 'A modal dialog was open, blocking this operation.',
|
| + 'An attempt was made to operate on a modal dialog when one was '
|
| + 'not open.',
|
| + 'A script did not complete before its timeout expired.',
|
| + 'The coordinates provided to an interactions operation are invalid.',
|
| + 'IME was not available.',
|
| + 'An IME engine could not be started.',
|
| + 'Argument was an invalid selector (e.g. XPath/CSS).',
|
| + 'A new session could not be created.',
|
| + 'Target provided for a move action is out of bounds.'
|
| + ];
|
| + }
|
| + if (statusCode < 0 || statusCode > 32) {
|
| + type = 'External';
|
| + details = '';
|
| + } else {
|
| + type = _errorTypes[statusCode];
|
| + details = _errorDetails[statusCode];
|
| + }
|
| + }
|
| +
|
| + String toString() {
|
| + return '$statusCode $type: $message $results\n$details';
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Base class for all WebDriver request classes. This class wraps up
|
| + * an URL prefix (host, port, and initial path), and provides a client
|
| + * function for doing HTTP requests with JSON payloads.
|
| + */
|
| +class WebDriverBase {
|
| +
|
| + String _host;
|
| + int _port;
|
| + String _path;
|
| + String _url;
|
| +
|
| + String get path => _path;
|
| + String get url => _url;
|
| +
|
| + /**
|
| + * The default URL for WebDriver remote server is
|
| + * http://localhost:4444/wd/hub.
|
| + */
|
| + WebDriverBase.fromUrl([this._url = 'http://localhost:4444/wd/hub']) {
|
| + // Break out the URL components.
|
| + var re = const RegExp('[^:/]+://([^/]+)(/.*)');
|
| + var matches = re.firstMatch(_url);
|
| + _host = matches[1];
|
| + _path = matches[2];
|
| + var idx = _host.indexOf(':');
|
| + if (idx >= 0) {
|
| + _port = parseInt(_host.substring(idx+1));
|
| + _host = _host.substring(0, idx);
|
| + } else {
|
| + _port = 80;
|
| + }
|
| + }
|
| +
|
| + WebDriverBase([
|
| + this._host = 'localhost',
|
| + this._port = 4444,
|
| + this._path = '/wd/hub']) {
|
| + _url = 'http://$_host:$_port$_path';
|
| + }
|
| +
|
| + /**
|
| + * Execute a request to the WebDriver server. [http_method] should be
|
| + * one of 'GET', 'POST', or 'DELETE'. [command] is the text to append
|
| + * to the base URL path to get the full URL. [params] are the additional
|
| + * parameters. If a [List] or [Map] they will be posted as JSON parameters.
|
| + * If a number or string, "/params" is appended to the URL.
|
| + */
|
| + void _serverRequest(String http_method, String command, Completer completer,
|
| + [List successCodes, Map params, Function customHandler]) {
|
| + var status = 0;
|
| + var results = null;
|
| + var message = null;
|
| + if (successCodes == null) {
|
| + successCodes = [ 200, 204 ];
|
| + }
|
| + try {
|
| + if (params != null && params is List && http_method != 'POST') {
|
| + throw new Exception(
|
| + 'The http method called for ${command} is ${http_method} but it has '
|
| + 'to be POST if you want to pass the JSON params '
|
| + '${JSON.stringify(params)}');
|
| + }
|
| +
|
| + var path = command;
|
| + if (params != null && (params is num || params is String)) {
|
| + path = '$path/$params';
|
| + }
|
| +
|
| + var client = new HttpClient();
|
| + var connection = client.open(http_method, _host, _port, path);
|
| +
|
| + connection.onRequest = (r) {
|
| + r.headers.add(HttpHeaders.ACCEPT, "application/json");
|
| + r.headers.add(
|
| + HttpHeaders.CONTENT_TYPE, 'application/json;charset=UTF-8');
|
| + OutputStream s = r.outputStream;
|
| + if (params != null && params is Map) {
|
| + s.writeString(JSON.stringify(params));
|
| + }
|
| + s.close();
|
| + };
|
| + connection.onError = (e) {
|
| + if (completer != null) {
|
| + completer.completeException(new WebDriverError(-1, e));
|
| + completer = null;
|
| + }
|
| + };
|
| + connection.followRedirects = false;
|
| + connection.onResponse = (r) {
|
| + StringInputStream s = new StringInputStream(r.inputStream);
|
| + StringBuffer sbuf = new StringBuffer();
|
| + s.onData = () {
|
| + var data = s.read();
|
| + if (data != null) {
|
| + sbuf.add(data);
|
| + }
|
| + };
|
| + s.onClosed = () {
|
| + var value = null;
|
| + results = sbuf.toString().trim();
|
| + // For some reason we get a bunch of NULs on the end
|
| + // of the text and the JSON parser blows up on these, so
|
| + // strip them. We have to do this the hard way as
|
| + // replaceAll('\0', '') does not work.
|
| + // These NULs can be seen in the TCP packet, so it is not
|
| + // an issue with character encoding; it seems to be a bug
|
| + // in WebDriver stack.
|
| + for (var i = results.length; --i >= 0;) {
|
| + var code = results.charCodeAt(i);
|
| + if (code != 0) {
|
| + results = results.substring(0, i+1);
|
| + break;
|
| + }
|
| + }
|
| + if (successCodes.indexOf(r.statusCode) < 0) {
|
| + throw 'Unexpected response ${r.statusCode}';
|
| + }
|
| + if (status == 0 && results.length > 0) {
|
| + // 4xx responses send plain text; others send JSON.
|
| + if (r.statusCode < 400) {
|
| + results = JSON.parse(results);
|
| + status = results['status'];
|
| + }
|
| + if (results is Map && (results as Map).containsKey('value')) {
|
| + value = results['value'];
|
| + }
|
| + if (value is Map && value.containsKey('message')) {
|
| + message = value['message'];
|
| + }
|
| + }
|
| + if (status == 0) {
|
| + if (customHandler != null) {
|
| + customHandler(r, value);
|
| + } else if (completer != null) {
|
| + completer.complete(value);
|
| + }
|
| + }
|
| + };
|
| + };
|
| + } catch (e, s) {
|
| + completer.completeException(
|
| + new WebDriverError(-1, e), s);
|
| + completer = null;
|
| + }
|
| + }
|
| +
|
| + Future _simpleCommand(method, extraPath, [successCodes, params]) {
|
| + var completer = new Completer();
|
| + _serverRequest(method, '${_path}/$extraPath', completer,
|
| + successCodes, params: params);
|
| + return completer.future;
|
| + }
|
| +
|
| + Future _get(extraPath, [successCodes]) =>
|
| + _simpleCommand('GET', extraPath, successCodes);
|
| +
|
| + Future _post(extraPath, [successCodes, params]) =>
|
| + _simpleCommand('POST', extraPath, successCodes, params);
|
| +
|
| + Future _delete(extraPath, [successCodes]) =>
|
| + _simpleCommand('DELETE', extraPath, successCodes);
|
| +}
|
| +
|
| +class WebDriver extends WebDriverBase {
|
| +
|
| + WebDriver(host, port, path) : super(host, port, path);
|
| +
|
| + /**
|
| + * Create a new session. The server will attempt to create a session that
|
| + * most closely matches the desired and required capabilities. Required
|
| + * capabilities have higher priority than desired capabilities and must be
|
| + * set for the session to be created.
|
| + *
|
| + * The capabilities are:
|
| + *
|
| + * - browserName (String) The name of the browser being used; should be one
|
| + * of chrome|firefox|htmlunit|internet explorer|iphone.
|
| + *
|
| + * - version (String) The browser version, or the empty string if unknown.
|
| + *
|
| + * - platform (String) A key specifying which platform the browser is
|
| + * running on. This value should be one of WINDOWS|XP|VISTA|MAC|LINUX|UNIX.
|
| + * When requesting a new session, the client may specify ANY to indicate
|
| + * any available platform may be used.
|
| + *
|
| + * - javascriptEnabled (bool) Whether the session supports executing user
|
| + * supplied JavaScript in the context of the current page.
|
| + *
|
| + * - takesScreenshot (bool) Whether the session supports taking screenshots
|
| + * of the current page.
|
| + *
|
| + * - handlesAlerts (bool) Whether the session can interact with modal popups,
|
| + * such as window.alert and window.confirm.
|
| + *
|
| + * - databaseEnabled (bool) Whether the session can interact database storage.
|
| + *
|
| + * - locationContextEnabled (bool) Whether the session can set and query the
|
| + * browser's location context.
|
| + *
|
| + * - applicationCacheEnabled (bool) Whether the session can interact with
|
| + * the application cache.
|
| + *
|
| + * - browserConnectionEnabled (bool) Whether the session can query for the
|
| + * browser's connectivity and disable it if desired.
|
| + *
|
| + * - cssSelectorsEnabled (bool) Whether the session supports CSS selectors
|
| + * when searching for elements.
|
| + *
|
| + * - webStorageEnabled (bool) Whether the session supports interactions with
|
| + * storage objects.
|
| + *
|
| + * - rotatable (bool) Whether the session can rotate the current page's
|
| + * current layout between portrait and landscape orientations (only applies
|
| + * to mobile platforms).
|
| + *
|
| + * - acceptSslCerts (bool) Whether the session should accept all SSL certs
|
| + * by default.
|
| + *
|
| + * - nativeEvents (bool) Whether the session is capable of generating native
|
| + * events when simulating user input.
|
| + *
|
| + * - proxy (proxy object) Details of any proxy to use. If no proxy is
|
| + * specified, whatever the system's current or default state is used.
|
| + *
|
| + * The format of the proxy object is:
|
| + *
|
| + * - proxyType (String) The type of proxy being used. Possible values are:
|
| + *
|
| + * direct - A direct connection - no proxy in use,
|
| + *
|
| + * manual - Manual proxy settings configured,
|
| + *
|
| + * pac - Proxy autoconfiguration from a URL),
|
| + *
|
| + * autodetect (proxy autodetection, probably with WPAD),
|
| + *
|
| + * system - Use system settings
|
| + *
|
| + * - proxyAutoconfigUrl (String) Required if proxyType == pac, Ignored
|
| + * otherwise. Specifies the URL to be used for proxy autoconfiguration.
|
| + *
|
| + * - ftpProxy, httpProxy, sslProxy (String) (Optional, Ignored if
|
| + * proxyType != manual) Specifies the proxies to be used for FTP, HTTP
|
| + * and HTTPS requests respectively. Behaviour is undefined if a request
|
| + * is made, where the proxy for the particular protocol is undefined,
|
| + * if proxyType is manual.
|
| + *
|
| + * Potential Errors: SessionNotCreatedException (if a required capability
|
| + * could not be set).
|
| + */
|
| + Future<WebDriverSession> newSession([
|
| + browser = 'chrome', Map additional_capabilities]) {
|
| + var completer = new Completer();
|
| + if (additional_capabilities == null) {
|
| + additional_capabilities = {};
|
| + }
|
| +
|
| + additional_capabilities['browserName'] = browser;
|
| +
|
| + _serverRequest('POST', '${_path}/session', null, [ 302 ],
|
| + customHandler: (r, v) {
|
| + var url = r.headers.value(HttpHeaders.LOCATION);
|
| + var session = new WebDriverSession.fromUrl(url);
|
| + completer.complete(session);
|
| + }, params: { 'desiredCapabilities': additional_capabilities });
|
| + return completer.future;
|
| + }
|
| +
|
| + /** Get the set of currently active sessions. */
|
| + Future<List<WebDriverSession>> getSessions() {
|
| + var completer = new Completer();
|
| + _get('sessions', (result) {
|
| + var _sessions = [];
|
| + for (var session in result) {
|
| + _sessions.add(new WebDriverSession.fromUrl(
|
| + '${this._path}/session/${session["id"]}'));
|
| + }
|
| + completer.complete(_sessions);
|
| + });
|
| + return completer.future;
|
| + }
|
| +
|
| + /** Query the server's current status. */
|
| + Future<Map> getStatus() => _get('status');
|
| +}
|
| +
|
| +class WebDriverWindow extends WebDriverBase {
|
| + WebDriverWindow.fromUrl(url) : super.fromUrl(url);
|
| +
|
| + /** Get the window size. */
|
| + Future<Map> getSize() => _get('size');
|
| +
|
| + /**
|
| + * Set the window size.
|
| + *
|
| + * Potential Errors:
|
| + * NoSuchWindow - If the specified window cannot be found.
|
| + */
|
| + Future<String> setSize(int width, int height) =>
|
| + _post('size', params: { 'width': width, 'height': height });
|
| +
|
| + /** Get the window position. */
|
| + Future<Map> getPosition() => _get('position');
|
| +
|
| + /**
|
| + * Set the window position.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future setPosition(int x, int y) =>
|
| + _post('position', params: { 'x': x, 'y': y });
|
| +
|
| + /** Maximize the specified window if not already maximized. */
|
| + Future maximize() => _post('maximize');
|
| +}
|
| +
|
| +class WebDriverSession extends WebDriverBase {
|
| + WebDriverSession.fromUrl(url) : super.fromUrl(url);
|
| +
|
| + /** Close the session. */
|
| + Future close() => _delete('');
|
| +
|
| + /** Get the session capabilities. See [newSession] for details. */
|
| + Future<Map> getCapabilities() => _get('');
|
| +
|
| + /**
|
| + * Configure the amount of time in milliseconds that a script can execute
|
| + * for before it is aborted and a Timeout error is returned to the client.
|
| + */
|
| + Future setScriptTimeout(t) =>
|
| + _post('timeouts', params: { 'type': 'script', 'ms': t });
|
| +
|
| + /*Future<String> setImplicitWaitTimeout(t) =>
|
| + simplePost('timeouts', { 'type': 'implicit', 'ms': t });*/
|
| +
|
| + /**
|
| + * Configure the amount of time in milliseconds that a page can load for
|
| + * before it is aborted and a Timeout error is returned to the client.
|
| + */
|
| + Future setPageLoadTimeout(t) =>
|
| + _post('timeouts', params: { 'type': 'page load', 'ms': t });
|
| +
|
| + /**
|
| + * Set the amount of time, in milliseconds, that asynchronous scripts
|
| + * executed by /session/:sessionId/execute_async are permitted to run
|
| + * before they are aborted and a Timeout error is returned to the client.
|
| + */
|
| + Future setAsyncScriptTimeout(t) =>
|
| + _post('timeouts/async_script', params: { 'ms': t });
|
| +
|
| + /**
|
| + * 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.
|
| + */
|
| + Future setImplicitWaitTimeout(t) =>
|
| + _post('timeouts/implicit_wait', params: { 'ms': t });
|
| +
|
| + /**
|
| + * Retrieve the current window handle.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<String> getWindowHandle() => _get('window_handle');
|
| +
|
| + /**
|
| + * Retrieve a [WebDriverWindow] for the specified window. We don't
|
| + * have to use a Future here but do so to be consistent.
|
| + */
|
| + Future<WebDriverWindow> getWindow([handle = 'current']) {
|
| + var completer = new Completer();
|
| + completer.complete(new WebDriverWindow.fromUrl('${_url}/window/$handle'));
|
| + return completer.future;
|
| + }
|
| +
|
| + /** Retrieve the list of all window handles available to the session. */
|
| + Future<List<String>> getWindowHandles() => _get('window_handles');
|
| +
|
| + /**
|
| + * Retrieve the URL of the current page.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<String> getUrl() => _get('url');
|
| +
|
| + /**
|
| + * Navigate to a new URL.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future setUrl(String url) => _post('url', params: { 'url': url });
|
| +
|
| + /**
|
| + * Navigate forwards in the browser history, if possible.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future navigateForward() => _post('forward');
|
| +
|
| + /**
|
| + * Navigate backwards in the browser history, if possible.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future navigateBack() => _post('back');
|
| +
|
| + /**
|
| + * Refresh the current page.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future refresh() => _post('refresh');
|
| +
|
| + /**
|
| + * 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.
|
| + *
|
| + * 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.
|
| + *
|
| + * Arguments may be any JSON-primitive, array, or JSON object. JSON objects
|
| + * that define a WebElement reference will be converted to the corresponding
|
| + * DOM element. Likewise, any WebElements in the script result will be
|
| + * returned to the client as WebElement JSON objects.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference, JavaScriptError.
|
| + */
|
| + Future execute(String script, [List args]) =>
|
| + _post('execute', params: { 'script': script, 'args': args });
|
| +
|
| + /**
|
| + * 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 it 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.
|
| + *
|
| + * 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.
|
| + *
|
| + * 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.
|
| + *
|
| + * Arguments may be any JSON-primitive, array, or JSON object. JSON objects
|
| + * that define a WebElement reference will be converted to the corresponding
|
| + * DOM element. Likewise, any WebElements in the script result will be
|
| + * returned to the client as WebElement JSON objects.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference, Timeout (controlled
|
| + * by the [setAsyncScriptTimeout] command), JavaScriptError (if the script
|
| + * callback is not invoked before the timout expires).
|
| + */
|
| + Future executeAsync(String script, [List args]) =>
|
| + _post('execute_async', params: { 'script': script, 'args': args });
|
| +
|
| + /**
|
| + * Take a screenshot of the current page (PNG).
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<List<int>> getScreenshot([fname]) {
|
| + var completer = new Completer();
|
| + var result = _serverRequest('GET', '$_path/screenshot', completer,
|
| + customHandler: (r, v) {
|
| + var image = Base64Decoder.decode(v);
|
| + if (fname != null) {
|
| + writeBytesToFile(fname, image);
|
| + }
|
| + completer.complete(image);
|
| + });
|
| + return completer.future;
|
| + }
|
| +
|
| + /**
|
| + * List all available IME (Input Method Editor) engines on the machine.
|
| + * To use an engine, it has to be present in this list.
|
| + *
|
| + * Potential Errors: ImeNotAvailableException.
|
| + */
|
| + Future<List<String>> getAvailableImeEngines() =>
|
| + _get('ime/available_engines');
|
| +
|
| + /**
|
| + * Get the name of the active IME engine. The name string is
|
| + * platform specific.
|
| + *
|
| + * Potential Errors: ImeNotAvailableException.
|
| + */
|
| + Future<String> getActiveImeEngine() => _get('ime/active_engine');
|
| +
|
| + /**
|
| + * Indicates whether IME input is active at the moment (not if
|
| + * it's available).
|
| + *
|
| + * Potential Errors: ImeNotAvailableException.
|
| + */
|
| + Future<bool> getIsImeActive() => _get('ime/activated');
|
| +
|
| + /**
|
| + * De-activates the currently-active IME engine.
|
| + *
|
| + * Potential Errors: ImeNotAvailableException.
|
| + */
|
| + Future deactivateIme() => _post('ime/deactivate');
|
| +
|
| + /**
|
| + * Make an engine that is available (appears on the list returned by
|
| + * getAvailableEngines) active. After this call, the engine will be added
|
| + * to the list of engines loaded in the IME daemon and the input sent using
|
| + * sendKeys will be converted by the active engine. Note that this is a
|
| + * platform-independent method of activating IME (the platform-specific way
|
| + * being using keyboard shortcuts).
|
| + *
|
| + * Potential Errors: ImeActivationFailedException, ImeNotAvailableException.
|
| + */
|
| + Future activateIme(String engine) =>
|
| + _post('ime/activate', params: { 'engine': engine });
|
| +
|
| + /**
|
| + * Change focus to another frame on the page. If the frame id is null,
|
| + * the server should switch to the page's default content.
|
| + * [id] is the Identifier for the frame to change focus to, and can be
|
| + * a string, number, null, or JSON Object.
|
| + *
|
| + * Potential Errors: NoSuchWindow, NoSuchFrame.
|
| + */
|
| + Future setFrameFocus(id) => _post('frame', params: { 'id': id });
|
| +
|
| + /**
|
| + * Change focus to another window. The window to change focus to may be
|
| + * specified by [name], which is its server assigned window handle, or
|
| + * the value of its name attribute.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future setWindowFocus(name) =>
|
| + _post('window', params: { 'name': name });
|
| +
|
| + /**
|
| + * Close the current window.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future closeWindow() => _delete('window');
|
| +
|
| + /**
|
| + * Retrieve all cookies visible to the current page.
|
| + *
|
| + * The returned List contains Maps with the following keys:
|
| + *
|
| + * 'name' - The name of the cookie.
|
| + *
|
| + * 'value' - The cookie value.
|
| + *
|
| + * The following keys may optionally be present:
|
| + *
|
| + * 'path' - The cookie path.
|
| + *
|
| + * 'domain' - The domain the cookie is visible to.
|
| + *
|
| + * 'secure' - Whether the cookie is a secure cookie.
|
| + *
|
| + * 'expiry' - When the cookie expires, seconds since midnight, 1/1/1970 UTC.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<List<Map>> getCookies() => _get('cookie');
|
| +
|
| + /**
|
| + * Set a cookie. If the cookie path is not specified, it should be set
|
| + * to "/". Likewise, if the domain is omitted, it should default to the
|
| + * current page's domain. See [getCookies] for the structure of a cookie
|
| + * Map.
|
| + */
|
| + Future setCookie(Map cookie) =>
|
| + _post('cookie', params: { 'cookie': cookie });
|
| +
|
| + /**
|
| + * Delete all cookies visible to the current page.
|
| + *
|
| + * Potential Errors: InvalidCookieDomain (the cookie's domain is not
|
| + * visible from the current page), NoSuchWindow, UnableToSetCookie (if
|
| + * attempting to set a cookie on a page that does not support cookies,
|
| + * e.g. pages with mime-type text/plain).
|
| + */
|
| + Future deleteCookies() => _delete('cookie');
|
| +
|
| + /**
|
| + * Delete the cookie with the given [name]. This command should be a no-op
|
| + * if there is no such cookie visible to the current page.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future deleteCookie(String name) => _delete('cookie/$name');
|
| +
|
| + /**
|
| + * Get the current page source.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<String> getPageSource() => _get('source');
|
| +
|
| + /**
|
| + * Get the current page title.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<String> getPageTitle() => _get('title');
|
| +
|
| + /**
|
| + * Search for an element on the page, starting from the document root. The
|
| + * first matching located element will be returned as a WebElement JSON
|
| + * object (a [Map] with an 'ELEMENT' key whose value should be used to
|
| + * identify the element in further requests). The [strategy] should be
|
| + * one of:
|
| + *
|
| + * 'class name' - Returns an element whose class name contains the search
|
| + * value; compound class names are not permitted.
|
| + *
|
| + * 'css selector' - Returns an element matching a CSS selector.
|
| + *
|
| + * 'id' - Returns an element whose ID attribute matches the search value.
|
| + *
|
| + * 'name' - Returns an element whose NAME attribute matches the search value.
|
| + *
|
| + * 'link text' - Returns an anchor element whose visible text matches the
|
| + * search value.
|
| + *
|
| + * 'partial link text' - Returns an anchor element whose visible text
|
| + * partially matches the search value.
|
| + *
|
| + * 'tag name' - Returns an element whose tag name matches the search value.
|
| + *
|
| + * 'xpath' - Returns an element matching an XPath expression.
|
| + *
|
| + * Potential Errors: NoSuchWindow, NoSuchElement, XPathLookupError (if
|
| + * using XPath and the input expression is invalid).
|
| + */
|
| + Future<String> findElement(String strategy, String searchValue) =>
|
| + _post('element', params: { 'using': strategy, 'value' : searchValue });
|
| +
|
| + /**
|
| + * Search for multiple elements on the page, starting from the document root.
|
| + * The located elements will be returned as WebElement JSON objects. See
|
| + * [findElement] for the locator strategies that each server supports.
|
| + * Elements are be returned in the order located in the DOM.
|
| + *
|
| + * Potential Errors: NoSuchWindow, XPathLookupError.
|
| + */
|
| + Future<List<String>> findElements(String strategy, String searchValue) =>
|
| + _post('elements', params: { 'using': strategy, 'value' : searchValue });
|
| +
|
| + /**
|
| + * Get the element on the page that currently has focus. The element will
|
| + * be returned as a WebElement JSON object.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<String> getElementWithFocus() => _post('element/active');
|
| +
|
| + /**
|
| + * Search for an element on the page, starting from element with id [id].
|
| + * The located element will be returned as WebElement JSON objects. See
|
| + * [findElement] for the locator strategies that each server supports.
|
| + *
|
| + * Potential Errors: NoSuchWindow, XPathLookupError.
|
| + */
|
| + Future<String>
|
| + findElementFromId(String id, String strategy, String searchValue) {
|
| + _post('element/$id/element',
|
| + params: { 'using': strategy, 'value' : searchValue });
|
| + }
|
| +
|
| + /**
|
| + * Search for multiple elements on the page, starting from the element with
|
| + * id [id].The located elements will be returned as WebElement JSON objects.
|
| + * See [findElement] for the locator strategies that each server supports.
|
| + * Elements are be returned in the order located in the DOM.
|
| + *
|
| + * Potential Errors: NoSuchWindow, XPathLookupError.
|
| + */
|
| + Future<List<String>>
|
| + findElementsFromId(String id, String strategy, String searchValue) =>
|
| + _post('element/$id/elements',
|
| + params: { 'using': strategy, 'value' : searchValue });
|
| +
|
| + /**
|
| + * Click on an element specified by [id].
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference, ElementNotVisible
|
| + * (if the referenced element is not visible on the page, either hidden
|
| + * by CSS, or has 0-width or 0-height).
|
| + */
|
| + Future clickElement(String id) => _post('element/$id/click');
|
| +
|
| + /**
|
| + * Submit a FORM element. The submit command may also be applied to any
|
| + * element that is a descendant of a FORM element.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference.
|
| + */
|
| + Future submit(String id) => _post('element/$id/submit');
|
| +
|
| + /** Returns the visible text for the element.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference.
|
| + */
|
| + Future<String> getElementText(String id) => _get('element/$id/text');
|
| +
|
| + /**
|
| + * 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 will 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:
|
| + *
|
| + * NULL - U+E000
|
| + *
|
| + * Cancel - U+E001
|
| + *
|
| + * Help - U+E002
|
| + *
|
| + * Backspace - U+E003
|
| + *
|
| + * Tab - U+E004
|
| + *
|
| + * Clear - U+E005
|
| + *
|
| + * Return - U+E006
|
| + *
|
| + * Enter - U+E007
|
| + *
|
| + * Shift - U+E008
|
| + *
|
| + * Control - U+E009
|
| + *
|
| + * Alt - U+E00A
|
| + *
|
| + * Pause - U+E00B
|
| + *
|
| + * Escape - U+E00C
|
| + *
|
| + * Space - U+E00D
|
| + *
|
| + * Pageup - U+E00E
|
| + *
|
| + * Pagedown - U+E00F
|
| + *
|
| + * End - U+E010
|
| + *
|
| + * Home - U+E011
|
| + *
|
| + * Left arrow - U+E012
|
| + *
|
| + * Up arrow - U+E013
|
| + *
|
| + * Right arrow - U+E014
|
| + *
|
| + * Down arrow - U+E015
|
| + *
|
| + * Insert - U+E016
|
| + *
|
| + * Delete - U+E017
|
| + *
|
| + * Semicolon - U+E018
|
| + *
|
| + * Equals - U+E019
|
| + *
|
| + * Numpad 0..9 - U+E01A..U+E023
|
| + *
|
| + * Multiply - U+E024
|
| + *
|
| + * Add - U+E025
|
| + *
|
| + * Separator - U+E026
|
| + *
|
| + * Subtract - U+E027
|
| + *
|
| + * Decimal - U+E028
|
| + *
|
| + * Divide - U+E029
|
| + *
|
| + * F1..F12 - U+E031..U+E03C
|
| + *
|
| + * Command/Meta U+E03D
|
| + *
|
| + * The server processes the key sequence as follows:
|
| + *
|
| + * - Each key that appears on the keyboard without requiring modifiers is
|
| + * sent as a keydown followed by a key up.
|
| + *
|
| + * - If the server does not support native events and must simulate key
|
| + * strokes with JavaScript, it will generate keydown, keypress, and keyup
|
| + * events, in that order. The keypress event is only fired when the
|
| + * corresponding key is for a printable character.
|
| + *
|
| + * - If a key requires a modifier key (e.g. "!" on a standard US keyboard),
|
| + * the sequence is: modifier down, key down, key up, modifier up, where
|
| + * key is the ideal unmodified key value (using the previous example,
|
| + * a "1").
|
| + *
|
| + * - Modifier keys (Ctrl, Shift, Alt, and Command/Meta) are assumed to be
|
| + * "sticky"; each modifier is held down (e.g. only a keydown event) until
|
| + * either the modifier is encountered again in the sequence, or the NULL
|
| + * (U+E000) key is encountered.
|
| + *
|
| + * - Each key sequence is terminated with an implicit NULL key.
|
| + * Subsequently, all depressed modifier keys are released (with
|
| + * corresponding keyup events) at the end of the sequence.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference, ElementNotVisible.
|
| + */
|
| + Future sendKeyStrokesToElement(String id, List<String> keys) =>
|
| + _post('element/$id/value', params: { 'value': keys });
|
| +
|
| + /**
|
| + * Send a sequence of key strokes to the active element. This command is
|
| + * similar to [sendKeyStrokesToElement] command in every aspect except the
|
| + * implicit termination: The modifiers are not released at the end of the
|
| + * call. Rather, the state of the modifier keys is kept between calls,
|
| + * so mouse interactions can be performed while modifier keys are depressed.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future sendKeyStrokes(List<String> keys) =>
|
| + _post('keys', params: { 'value': keys });
|
| +
|
| + /**
|
| + * Query for an element's tag name, as a lower-case string.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference.
|
| + */
|
| + Future<String> getElementTagName(String id) => _get('element/$id/name');
|
| +
|
| + /**
|
| + * Clear a TEXTAREA or text INPUT element's value.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference, ElementNotVisible,
|
| + * InvalidElementState.
|
| + */
|
| + Future clearValue(String id) => _post('/element/$id/clear');
|
| +
|
| + /**
|
| + * Determine if an OPTION element, or an INPUT element of type checkbox
|
| + * or radiobutton is currently selected.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference.
|
| + */
|
| + Future<bool> isSelected(String id) => _get('element/$id/selected');
|
| +
|
| + /**
|
| + * Determine if an element is currently enabled.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference.
|
| + */
|
| + Future<bool> isEnabled(String id) => _get('element/$id/enabled');
|
| +
|
| + /**
|
| + * Get the value of an element's attribute, or null if it has no such
|
| + * attribute.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference.
|
| + */
|
| + Future<String> getAttribute(String id, String attribute) =>
|
| + _get('element/$id/attribute/$attribute');
|
| +
|
| + /**
|
| + * Test if two element IDs refer to the same DOM element.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference.
|
| + */
|
| + Future<bool> areSameElement(String id, String other) =>
|
| + _get('element/$id/equals/$other');
|
| +
|
| + /**
|
| + * Determine if an element is currently displayed.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference.
|
| + */
|
| + Future<bool> isDiplayed(String id) => _get('element/$id/displayed');
|
| +
|
| + /**
|
| + * Determine an element's location on the page. The point (0, 0) refers to
|
| + * the upper-left corner of the page. The element's coordinates are returned
|
| + * as a [Map] object with x and y properties.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference.
|
| + */
|
| + Future<Map> getElementLocation(String id) => _get('element/$id/location');
|
| +
|
| + /**
|
| + * Determine an element's size in pixels. The size will be returned as a
|
| + * [Map] object with width and height properties.
|
| + *
|
| + * Potential Errors: NoSuchWindow, StalElementReference.
|
| + */
|
| + Future<Map> getElementSize(String id) => _get('element/$id/size');
|
| +
|
| + /**
|
| + * Query the value of an element's computed CSS property. The CSS property
|
| + * to query should be specified using the CSS property name, not the
|
| + * JavaScript property name (e.g. background-color instead of
|
| + * backgroundColor).
|
| + *
|
| + * Potential Errors: NoSuchWindow, StaleElementReference.
|
| + */
|
| + Future<String> getElementCssProperty(String id, String property) =>
|
| + _get('element/$id/css/$property');
|
| +
|
| + /**
|
| + * Get the current browser orientation ('LANDSCAPE' or 'PORTRAIT').
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<String> getBrowserOrientation() => _get('orientation');
|
| +
|
| + /**
|
| + * Gets the text of the currently displayed JavaScript alert(), confirm(),
|
| + * or prompt() dialog.
|
| + *
|
| + * Potential Errors: NoAlertPresent.
|
| + */
|
| + Future<String> getAlertText() => _get('alert_text');
|
| +
|
| + /**
|
| + * Sends keystrokes to a JavaScript prompt() dialog.
|
| + *
|
| + * Potential Errors: NoAlertPresent.
|
| + */
|
| + Future sendKeyStrokesToPrompt(String text) =>
|
| + _post('alert_text', params: { 'text': text });
|
| +
|
| + /**
|
| + * Accepts the currently displayed alert dialog. Usually, this is equivalent
|
| + * to clicking on the 'OK' button in the dialog.
|
| + *
|
| + * Potential Errors: NoAlertPresent.
|
| + */
|
| + Future acceptAlert() => _post('accept_alert');
|
| +
|
| + /**
|
| + * Dismisses the currently displayed alert dialog. For confirm() and prompt()
|
| + * dialogs, this is equivalent to clicking the 'Cancel' button. For alert()
|
| + * dialogs, this is equivalent to clicking the 'OK' button.
|
| + *
|
| + * Potential Errors: NoAlertPresent.
|
| + */
|
| + Future dismissAlert() => _post('dismiss_alert');
|
| +
|
| + /**
|
| + * Move the mouse by an offset of the specificed element. If no element is
|
| + * specified, the move is relative to the current mouse cursor. If an
|
| + * element is provided but no offset, the mouse will be moved to the center
|
| + * of the element. If the element is not visible, it will be scrolled
|
| + * into view.
|
| + */
|
| + Future moveTo(String id, int x, int y) =>
|
| + _post('moveto', params: { 'element': id, 'xoffset': x, 'yoffset' : y});
|
| +
|
| + /**
|
| + * Click a mouse button (at the coordinates set by the last [moveTo] command).
|
| + * Note that calling this command after calling [buttonDown] and before
|
| + * calling [buttonUp] (or any out-of-order interactions sequence) will yield
|
| + * undefined behaviour).
|
| + *
|
| + * [button] should be 0 for left, 1 for middle, or 2 for right.
|
| + */
|
| + Future clickMouse([button = 0]) =>
|
| + _post('click', params: { 'button' : button });
|
| +
|
| + /**
|
| + * Click and hold the left mouse button (at the coordinates set by the last
|
| + * [moveTo] command). Note that the next mouse-related command that should
|
| + * follow is [buttonDown]. Any other mouse command (such as [click] or
|
| + * another call to [buttonDown]) will yield undefined behaviour.
|
| + *
|
| + * [button] should be 0 for left, 1 for middle, or 2 for right.
|
| + */
|
| + Future buttonDown([button = 0]) =>
|
| + _post('click', params: { 'button' : button });
|
| +
|
| + /**
|
| + * Releases the mouse button previously held (where the mouse is currently
|
| + * at). Must be called once for every [buttonDown] command issued. See the
|
| + * note in [click] and [buttonDown] about implications of out-of-order
|
| + * commands.
|
| + *
|
| + * [button] should be 0 for left, 1 for middle, or 2 for right.
|
| + */
|
| + Future buttonUp([button = 0]) =>
|
| + _post('click', params: { 'button' : button });
|
| +
|
| + /** Double-clicks at the current mouse coordinates (set by [moveTo]). */
|
| + Future doubleClick() => _post('doubleclick');
|
| +
|
| + /** Single tap on the touch enabled device on the element with id [id]. */
|
| + Future touchClick(String id) =>
|
| + _post('touch/click', params: { 'element': id });
|
| +
|
| + /** Finger down on the screen. */
|
| + Future touchDown(int x, int y) =>
|
| + _post('touch/down', params: { 'x': x, 'y': y });
|
| +
|
| + /** Finger up on the screen. */
|
| + Future touchUp(int x, int y) =>
|
| + _post('touch/up', params: { 'x': x, 'y': y });
|
| +
|
| + /** Finger move on the screen. */
|
| + Future touchMove(int x, int y) =>
|
| + _post('touch/move', params: { 'x': x, 'y': y });
|
| +
|
| + /**
|
| + * Scroll on the touch screen using finger based motion events. If [id] is
|
| + * specified, scrolling will start at a particular screen location.
|
| + */
|
| + Future touchScroll(int xOffset, int yOffset, [String id = null]) {
|
| + if (id == null) {
|
| + return _post('touch/scroll',
|
| + params: { 'xoffset': xOffset, 'yoffset': yOffset });
|
| + } else {
|
| + return _post('touch/scroll',
|
| + params: { 'element': id, 'xoffset': xOffset, 'yoffset': yOffset });
|
| + }
|
| + }
|
| +
|
| + /** Double tap on the touch screen using finger motion events. */
|
| + Future touchDoubleClick(String id) =>
|
| + _post('touch/doubleclick', params: { 'element': id });
|
| +
|
| + /** Long press on the touch screen using finger motion events. */
|
| + Future touchLongClick(String id) =>
|
| + _post('touch/longclick', params: { 'element': id });
|
| +
|
| + /**
|
| + * Flick on the touch screen using finger based motion events, starting
|
| + * at a particular screen location. [speed] is in pixels-per-second.
|
| + */
|
| + Future touchFlickFrom(String id, int xOffset, int yOffset, int speed) =>
|
| + _post('touch/flick',
|
| + params: { 'element': id, 'xoffset': xOffset, 'yoffset': yOffset,
|
| + 'speed': speed });
|
| +
|
| + /**
|
| + * Flick on the touch screen using finger based motion events. Use this
|
| + * instead of [touchFlickFrom] if you don'tr care where the flick starts.
|
| + */
|
| + Future touchFlick(int xSpeed, int ySpeed) =>
|
| + _post('touch/flick', params: { 'xSpeed': xSpeed, 'ySpeed': ySpeed });
|
| +
|
| + /**
|
| + * Get the current geo location. Returns a [Map] with latitude,
|
| + * longitude and altitude properties.
|
| + */
|
| + Future<Map> getGeolocation() => _get('location');
|
| +
|
| + /** Set the current geo location. */
|
| + Future setLocation(double latitude, double longitude, double altitude) =>
|
| + _post('location', params:
|
| + { 'latitude': latitude,
|
| + 'longitude': longitude,
|
| + 'altitude': altitude });
|
| +
|
| + /**
|
| + * Get all keys of the local storage. Completes with [null] if there
|
| + * are no keys or the keys could not be retrieved.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<List<String>> getLocalStorageKeys() => _get('local_storage');
|
| +
|
| + /**
|
| + * Set the local storage item for the given key.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future setLocalStorageItem(String key, String value) =>
|
| + _post('local_storage', params: { 'key': key, 'value': value });
|
| +
|
| + /**
|
| + * Clear the local storage.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future clearLocalStorage() => _delete('local_storage');
|
| +
|
| + /**
|
| + * Get the local storage item for the given key.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<String> getLocalStorageValue(String key) =>
|
| + _get('local_storage/key/$key');
|
| +
|
| + /**
|
| + * Delete the local storage item for the given key.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future deleteLocalStorageValue(String key) =>
|
| + _delete('local_storage/key/$key');
|
| +
|
| + /**
|
| + * Get the number of items in the local storage.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<int> getLocalStorageCount() => _get('local_storage/size');
|
| +
|
| + /**
|
| + * Get all keys of the session storage.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<List<String>> getSessionStorageKeys() => _get('session_storage');
|
| +
|
| + /**
|
| + * Set the sessionstorage item for the given key.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future setSessionStorageItem(String key, String value) =>
|
| + _post('session_storage', params: { 'key': key, 'value': value });
|
| +
|
| + /**
|
| + * Clear the session storage.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future clearSessionStorage() => _delete('session_storage');
|
| +
|
| + /**
|
| + * Get the session storage item for the given key.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<String> getSessionStorageValue(String key) =>
|
| + _get('session_storage/key/$key');
|
| +
|
| + /**
|
| + * Delete the session storage item for the given key.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future deleteSessionStorageValue(String key) =>
|
| + _delete('session_storage/key/$key');
|
| +
|
| + /**
|
| + * Get the number of items in the session storage.
|
| + *
|
| + * Potential Errors: NoSuchWindow.
|
| + */
|
| + Future<String> getSessionStorageCount() => _get('session_storage/size');
|
| +
|
| + /** Get available log types ('client', 'driver', 'browser', 'server'). */
|
| + Future<List<String>> getLogTypes() => _get('log/types');
|
| +
|
| + /**
|
| + * Get the log for a given log type. Log buffer is reset after each request.
|
| + * Each log entry is a [Map] with these fields:
|
| + *
|
| + * 'timestamp' (int) - The timestamp of the entry.
|
| + * 'level' (String) - The log level of the entry, for example, "INFO".
|
| + * 'message' (String) - The log message.
|
| + */
|
| + Future<List<Map>> getLogs(String type) =>
|
| + _post('log', params: { 'type': type });
|
| +}
|
|
|