Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1463)

Unified Diff: pkg/webdriver/lib/webdriver.dart

Issue 12413012: Bring webdriver up to date with SDK changes, and a bit of refactoring. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/webdriver/test/webdriver_test.dart » ('j') | pkg/webdriver/test/webdriver_test.dart » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/webdriver/lib/webdriver.dart
===================================================================
--- pkg/webdriver/lib/webdriver.dart (revision 19698)
+++ pkg/webdriver/lib/webdriver.dart (working copy)
@@ -7,6 +7,7 @@
import 'dart:json' as json;
import 'dart:uri';
import 'dart:io';
+import 'dart:async';
part 'src/base64decoder.dart';
@@ -33,18 +34,18 @@
* String id;
* WebDriverSession session;
* Future f = web_driver.newSession('chrome');
- * f.chain((_session) {
+ * f.then((_session) {
* session = _session;
* return session.setUrl('http://my.web.site.com');
- * }).chain((_) {
+ * }).then((_) {
* return session.findElement('id', 'username');
- * }).chain((element) {
+ * }).then((element) {
* id = element['ELEMENT'];
* return session.sendKeyStrokesToElement(id,
* [ 'j', 'o', 'e', ' ', 'u', 's', 'e', 'r' ]);
- * }).chain((_) {
+ * }).then((_) {
* return session.submit(id);
- * }).chain((_) {
+ * }).then((_) {
* return session.close();
* }).then((_) {
* session = null;
@@ -222,7 +223,7 @@
* 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]) {
+ {List successCodes, Map params, Function customHandler}) {
var status = 0;
var results = null;
var message = null;
@@ -230,88 +231,85 @@
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';
+ if (params != null) {
+ if (params is num || params is String) {
+ path = '$path/$params';
+ params = null;
+ } else if (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 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(
+ client.open(http_method, _host, _port, path).then((req) {
+ req.followRedirects = false;
+ req.headers.add(HttpHeaders.ACCEPT, "application/json");
+ req.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));
+ if (params != null) {
+ var body = json.stringify(params);
+ req.write(body);
}
- s.close();
- };
- connection.onError = (e) {
- if (completer != null) {
- completer.completeError(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.write(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.parse blows up on these, so
- // strip them.
- // 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.codeUnitAt(i);
- if (code != 0) {
- results = results.substring(0, i + 1);
- break;
+ req.close().then((rsp) {
+ List<int> body = new List<int>();
+ rsp.listen(body.addAll, onDone: () {
+ var value = null;
+ results = new String.fromCharCodes(body);
+ // For some reason we get a bunch of NULs on the end
+ // of the text and the json.parse blows up on these, so
+ // strip them.
+ // 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.codeUnitAt(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 (successCodes.indexOf(rsp.statusCode) < 0) {
+ throw 'Unexpected response ${rsp.statusCode}; $results';
}
- if (results is Map && (results as Map).containsKey('value')) {
- value = results['value'];
+ if (status == 0 && results.length > 0) {
+ // 4xx responses send plain text; others send JSON.
+ if (rsp.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 (value is Map && value.containsKey('message')) {
- message = value['message'];
+ if (status == 0) {
+ if (customHandler != null) {
+ customHandler(rsp, value);
+ } else if (completer != null) {
+ completer.complete(value);
+ }
}
+ });
+ })
+ .catchError((e) {
+ if (completer != null) {
+ completer.completeError(new WebDriverError(-1, e));
+ completer = null;
}
- if (status == 0) {
- if (customHandler != null) {
- customHandler(r, value);
- } else if (completer != null) {
- completer.complete(value);
- }
- }
- };
- };
+ });
+ })
+ .catchError((e) {
+ if (completer != null) {
+ completer.completeError(new WebDriverError(-1, e));
+ completer = null;
+ }
+ });
} catch (e, s) {
completer.completeError(
new WebDriverError(-1, e), s);
@@ -319,21 +317,28 @@
}
}
- Future _simpleCommand(method, extraPath, [successCodes, params]) {
+ Future _get(String extraPath) {
var completer = new Completer();
- _serverRequest(method, '${_path}/$extraPath', completer,
- successCodes, params: params);
+ _serverRequest('GET', '${_path}/$extraPath', completer);
return completer.future;
}
- Future _get(extraPath, [successCodes]) =>
- _simpleCommand('GET', extraPath, successCodes);
+ Future _getCustom(String extraPath, Function customHandler) =>
+ _serverRequest('GET', '${_path}/$extraPath', null,
+ customHandler: customHandler);
- Future _post(extraPath, [successCodes, params]) =>
- _simpleCommand('POST', extraPath, successCodes, params);
+ Future _post(String extraPath, [String params]) {
+ var completer = new Completer();
+ _serverRequest('POST', '${_path}/$extraPath', completer,
+ params: params);
+ return completer.future;
+ }
- Future _delete(extraPath, [successCodes]) =>
- _simpleCommand('DELETE', extraPath, successCodes);
+ Future _delete(String extraPath) {
+ var completer = new Completer();
+ _serverRequest('DELETE', '${_path}/$extraPath', completer);
+ return completer.future;
+ }
}
class WebDriver extends WebDriverBase {
@@ -432,23 +437,26 @@
additional_capabilities['browserName'] = browser;
- _serverRequest('POST', '${_path}/session', null, [ 302 ],
+ _serverRequest('POST', '${_path}/session', null,
+ successCodes: [ 302 ],
customHandler: (r, v) {
var url = r.headers.value(HttpHeaders.LOCATION);
var session = new WebDriverSession.fromUrl(url);
completer.complete(session);
- }, params: { 'desiredCapabilities': additional_capabilities });
+ },
+ 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) {
+ _getCustom('sessions', (r, v) {
var _sessions = [];
- for (var session in result) {
- _sessions.add(new WebDriverSession.fromUrl(
- '${this._path}/session/${session["id"]}'));
+ for (var session in v) {
+ var url = 'http://${this._host}:${this._port}${this._path}/'
+ 'session/${session["id"]}';
+ _sessions.add(new WebDriverSession.fromUrl(url));
}
completer.complete(_sessions);
});
@@ -472,7 +480,7 @@
* NoSuchWindow - If the specified window cannot be found.
*/
Future<String> setSize(int width, int height) =>
- _post('size', params: { 'width': width, 'height': height });
+ _post('size', { 'width': width, 'height': height });
/** Get the window position. */
Future<Map> getPosition() => _get('position');
@@ -483,7 +491,7 @@
* Potential Errors: NoSuchWindow.
*/
Future setPosition(int x, int y) =>
- _post('position', params: { 'x': x, 'y': y });
+ _post('position', { 'x': x, 'y': y });
/** Maximize the specified window if not already maximized. */
Future maximize() => _post('maximize');
@@ -503,7 +511,7 @@
* for before it is aborted and a Timeout error is returned to the client.
*/
Future setScriptTimeout(t) =>
- _post('timeouts', params: { 'type': 'script', 'ms': t });
+ _post('timeouts', { 'type': 'script', 'ms': t });
/*Future<String> setImplicitWaitTimeout(t) =>
simplePost('timeouts', { 'type': 'implicit', 'ms': t });*/
@@ -513,7 +521,7 @@
* before it is aborted and a Timeout error is returned to the client.
*/
Future setPageLoadTimeout(t) =>
- _post('timeouts', params: { 'type': 'page load', 'ms': t });
+ _post('timeouts', { 'type': 'page load', 'ms': t });
/**
* Set the amount of time, in milliseconds, that asynchronous scripts
@@ -521,7 +529,7 @@
* before they are aborted and a Timeout error is returned to the client.
*/
Future setAsyncScriptTimeout(t) =>
- _post('timeouts/async_script', params: { 'ms': t });
+ _post('timeouts/async_script', { 'ms': t });
/**
* Set the amount of time the driver should wait when searching for elements.
@@ -535,7 +543,7 @@
* wait of 0ms.
*/
Future setImplicitWaitTimeout(t) =>
- _post('timeouts/implicit_wait', params: { 'ms': t });
+ _post('timeouts/implicit_wait', { 'ms': t });
/**
* Retrieve the current window handle.
@@ -569,7 +577,7 @@
*
* Potential Errors: NoSuchWindow.
*/
- Future setUrl(String url) => _post('url', params: { 'url': url });
+ Future setUrl(String url) => _post('url', { 'url': url });
/**
* Navigate forwards in the browser history, if possible.
@@ -612,7 +620,7 @@
* Potential Errors: NoSuchWindow, StaleElementReference, JavaScriptError.
*/
Future execute(String script, [List args]) =>
- _post('execute', params: { 'script': script, 'args': args });
+ _post('execute', { 'script': script, 'args': args });
/**
* Inject a snippet of JavaScript into the page for execution in the context
@@ -641,7 +649,7 @@
* callback is not invoked before the timout expires).
*/
Future executeAsync(String script, [List args]) =>
- _post('execute_async', params: { 'script': script, 'args': args });
+ _post('execute_async', { 'script': script, 'args': args });
/**
* Take a screenshot of the current page (PNG).
@@ -704,7 +712,7 @@
* Potential Errors: ImeActivationFailedException, ImeNotAvailableException.
*/
Future activateIme(String engine) =>
- _post('ime/activate', params: { 'engine': engine });
+ _post('ime/activate', { 'engine': engine });
/**
* Change focus to another frame on the page. If the frame id is null,
@@ -714,7 +722,7 @@
*
* Potential Errors: NoSuchWindow, NoSuchFrame.
*/
- Future setFrameFocus(id) => _post('frame', params: { 'id': id });
+ Future setFrameFocus(id) => _post('frame', { 'id': id });
/**
* Change focus to another window. The window to change focus to may be
@@ -723,8 +731,7 @@
*
* Potential Errors: NoSuchWindow.
*/
- Future setWindowFocus(name) =>
- _post('window', params: { 'name': name });
+ Future setWindowFocus(name) => _post('window', { 'name': name });
/**
* Close the current window.
@@ -762,8 +769,7 @@
* current page's domain. See [getCookies] for the structure of a cookie
* Map.
*/
- Future setCookie(Map cookie) =>
- _post('cookie', params: { 'cookie': cookie });
+ Future setCookie(Map cookie) => _post('cookie', { 'cookie': cookie });
/**
* Delete all cookies visible to the current page.
@@ -827,7 +833,7 @@
* using XPath and the input expression is invalid).
*/
Future<String> findElement(String strategy, String searchValue) =>
- _post('element', params: { 'using': strategy, 'value' : searchValue });
+ _post('element', { 'using': strategy, 'value' : searchValue });
/**
* Search for multiple elements on the page, starting from the document root.
@@ -838,7 +844,7 @@
* Potential Errors: NoSuchWindow, XPathLookupError.
*/
Future<List<String>> findElements(String strategy, String searchValue) =>
- _post('elements', params: { 'using': strategy, 'value' : searchValue });
+ _post('elements', { 'using': strategy, 'value' : searchValue });
/**
* Get the element on the page that currently has focus. The element will
@@ -857,8 +863,7 @@
*/
Future<String>
findElementFromId(String id, String strategy, String searchValue) {
- _post('element/$id/element',
- params: { 'using': strategy, 'value' : searchValue });
+ _post('element/$id/element', { 'using': strategy, 'value' : searchValue });
}
/**
@@ -1002,7 +1007,7 @@
* Potential Errors: NoSuchWindow, StaleElementReference, ElementNotVisible.
*/
Future sendKeyStrokesToElement(String id, List<String> keys) =>
- _post('element/$id/value', params: { 'value': keys });
+ _post('element/$id/value', { 'value': keys });
/**
* Send a sequence of key strokes to the active element. This command is
@@ -1013,8 +1018,7 @@
*
* Potential Errors: NoSuchWindow.
*/
- Future sendKeyStrokes(List<String> keys) =>
- _post('keys', params: { 'value': keys });
+ Future sendKeyStrokes(List<String> keys) => _post('keys', { 'value': keys });
/**
* Query for an element's tag name, as a lower-case string.
@@ -1119,7 +1123,7 @@
* Potential Errors: NoAlertPresent.
*/
Future sendKeyStrokesToPrompt(String text) =>
- _post('alert_text', params: { 'text': text });
+ _post('alert_text', { 'text': text });
/**
* Accepts the currently displayed alert dialog. Usually, this is equivalent
@@ -1146,7 +1150,7 @@
* into view.
*/
Future moveTo(String id, int x, int y) =>
- _post('moveto', params: { 'element': id, 'xoffset': x, 'yoffset' : y});
+ _post('moveto', { 'element': id, 'xoffset': x, 'yoffset' : y});
/**
* Click a mouse button (at the coordinates set by the last [moveTo] command).
@@ -1156,8 +1160,7 @@
*
* [button] should be 0 for left, 1 for middle, or 2 for right.
*/
- Future clickMouse([button = 0]) =>
- _post('click', params: { 'button' : button });
+ Future clickMouse([button = 0]) => _post('click', { 'button' : button });
/**
* Click and hold the left mouse button (at the coordinates set by the last
@@ -1167,8 +1170,7 @@
*
* [button] should be 0 for left, 1 for middle, or 2 for right.
*/
- Future buttonDown([button = 0]) =>
- _post('click', params: { 'button' : button });
+ Future buttonDown([button = 0]) => _post('click', { 'button' : button });
/**
* Releases the mouse button previously held (where the mouse is currently
@@ -1178,27 +1180,22 @@
*
* [button] should be 0 for left, 1 for middle, or 2 for right.
*/
- Future buttonUp([button = 0]) =>
- _post('click', params: { 'button' : button });
+ Future buttonUp([button = 0]) => _post('click', { '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 });
+ Future touchClick(String id) => _post('touch/click', { 'element': id });
/** Finger down on the screen. */
- Future touchDown(int x, int y) =>
- _post('touch/down', params: { 'x': x, 'y': y });
+ Future touchDown(int x, int y) => _post('touch/down', { 'x': x, 'y': y });
/** Finger up on the screen. */
- Future touchUp(int x, int y) =>
- _post('touch/up', params: { 'x': x, 'y': y });
+ Future touchUp(int x, int y) => _post('touch/up', { 'x': x, 'y': y });
/** Finger move on the screen. */
- Future touchMove(int x, int y) =>
- _post('touch/move', params: { 'x': x, 'y': y });
+ Future touchMove(int x, int y) => _post('touch/move', { 'x': x, 'y': y });
/**
* Scroll on the touch screen using finger based motion events. If [id] is
@@ -1206,21 +1203,20 @@
*/
Future touchScroll(int xOffset, int yOffset, [String id = null]) {
if (id == null) {
- return _post('touch/scroll',
- params: { 'xoffset': xOffset, 'yoffset': yOffset });
+ return _post('touch/scroll', { 'xoffset': xOffset, 'yoffset': yOffset });
} else {
return _post('touch/scroll',
- params: { 'element': id, 'xoffset': xOffset, 'yoffset': yOffset });
+ { '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 });
+ _post('touch/doubleclick', { 'element': id });
/** Long press on the touch screen using finger motion events. */
Future touchLongClick(String id) =>
- _post('touch/longclick', params: { 'element': id });
+ _post('touch/longclick', { 'element': id });
/**
* Flick on the touch screen using finger based motion events, starting
@@ -1228,7 +1224,7 @@
*/
Future touchFlickFrom(String id, int xOffset, int yOffset, int speed) =>
_post('touch/flick',
- params: { 'element': id, 'xoffset': xOffset, 'yoffset': yOffset,
+ { 'element': id, 'xoffset': xOffset, 'yoffset': yOffset,
'speed': speed });
/**
@@ -1236,7 +1232,7 @@
* 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 });
+ _post('touch/flick', { 'xSpeed': xSpeed, 'ySpeed': ySpeed });
/**
* Get the current geo location. Returns a [Map] with latitude,
@@ -1246,7 +1242,7 @@
/** Set the current geo location. */
Future setLocation(double latitude, double longitude, double altitude) =>
- _post('location', params:
+ _post('location',
{ 'latitude': latitude,
'longitude': longitude,
'altitude': altitude });
@@ -1265,7 +1261,7 @@
* Potential Errors: NoSuchWindow.
*/
Future setLocalStorageItem(String key, String value) =>
- _post('local_storage', params: { 'key': key, 'value': value });
+ _post('local_storage', { 'key': key, 'value': value });
/**
* Clear the local storage.
@@ -1310,7 +1306,7 @@
* Potential Errors: NoSuchWindow.
*/
Future setSessionStorageItem(String key, String value) =>
- _post('session_storage', params: { 'key': key, 'value': value });
+ _post('session_storage', { 'key': key, 'value': value });
/**
* Clear the session storage.
@@ -1353,6 +1349,5 @@
* '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 });
+ Future<List<Map>> getLogs(String type) => _post('log', { 'type': type });
}
« no previous file with comments | « no previous file | pkg/webdriver/test/webdriver_test.dart » ('j') | pkg/webdriver/test/webdriver_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698