| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library webdriver; | 5 library webdriver; |
| 6 | 6 |
| 7 import 'dart:json'; | 7 import 'dart:json' as json; |
| 8 import 'dart:uri'; | 8 import 'dart:uri'; |
| 9 import 'dart:io'; | 9 import 'dart:io'; |
| 10 import 'dart:math'; | |
| 11 | 10 |
| 12 part 'src/base64decoder.dart'; | 11 part 'src/base64decoder.dart'; |
| 13 | 12 |
| 14 /** | 13 /** |
| 15 * WebDriver bindings for Dart. | 14 * WebDriver bindings for Dart. |
| 16 * | 15 * |
| 17 * These bindings are based on the WebDriver JSON wire protocol spec | 16 * These bindings are based on the WebDriver JSON wire protocol spec |
| 18 * (http://code.google.com/p/selenium/wiki/JsonWireProtocol). Not | 17 * (http://code.google.com/p/selenium/wiki/JsonWireProtocol). Not |
| 19 * all of these commands are implemented yet by WebDriver itself. | 18 * all of these commands are implemented yet by WebDriver itself. |
| 20 * Nontheless this is a complete implementation of the spec as the | 19 * Nontheless this is a complete implementation of the spec as the |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 * http://localhost:4444/wd/hub. | 199 * http://localhost:4444/wd/hub. |
| 201 */ | 200 */ |
| 202 WebDriverBase.fromUrl([this._url = 'http://localhost:4444/wd/hub']) { | 201 WebDriverBase.fromUrl([this._url = 'http://localhost:4444/wd/hub']) { |
| 203 // Break out the URL components. | 202 // Break out the URL components. |
| 204 var re = new RegExp('[^:/]+://([^/]+)(/.*)'); | 203 var re = new RegExp('[^:/]+://([^/]+)(/.*)'); |
| 205 var matches = re.firstMatch(_url); | 204 var matches = re.firstMatch(_url); |
| 206 _host = matches[1]; | 205 _host = matches[1]; |
| 207 _path = matches[2]; | 206 _path = matches[2]; |
| 208 var idx = _host.indexOf(':'); | 207 var idx = _host.indexOf(':'); |
| 209 if (idx >= 0) { | 208 if (idx >= 0) { |
| 210 _port = parseInt(_host.substring(idx+1)); | 209 _port = int.parse(_host.substring(idx+1)); |
| 211 _host = _host.substring(0, idx); | 210 _host = _host.substring(0, idx); |
| 212 } else { | 211 } else { |
| 213 _port = 80; | 212 _port = 80; |
| 214 } | 213 } |
| 215 } | 214 } |
| 216 | 215 |
| 217 WebDriverBase([ | 216 WebDriverBase([ |
| 218 this._host = 'localhost', | 217 this._host = 'localhost', |
| 219 this._port = 4444, | 218 this._port = 4444, |
| 220 this._path = '/wd/hub']) { | 219 this._path = '/wd/hub']) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 234 var results = null; | 233 var results = null; |
| 235 var message = null; | 234 var message = null; |
| 236 if (successCodes == null) { | 235 if (successCodes == null) { |
| 237 successCodes = [ 200, 204 ]; | 236 successCodes = [ 200, 204 ]; |
| 238 } | 237 } |
| 239 try { | 238 try { |
| 240 if (params != null && params is List && http_method != 'POST') { | 239 if (params != null && params is List && http_method != 'POST') { |
| 241 throw new Exception( | 240 throw new Exception( |
| 242 'The http method called for ${command} is ${http_method} but it has ' | 241 'The http method called for ${command} is ${http_method} but it has ' |
| 243 'to be POST if you want to pass the JSON params ' | 242 'to be POST if you want to pass the JSON params ' |
| 244 '${JSON.stringify(params)}'); | 243 '${json.stringify(params)}'); |
| 245 } | 244 } |
| 246 | 245 |
| 247 var path = command; | 246 var path = command; |
| 248 if (params != null && (params is num || params is String)) { | 247 if (params != null && (params is num || params is String)) { |
| 249 path = '$path/$params'; | 248 path = '$path/$params'; |
| 250 } | 249 } |
| 251 | 250 |
| 252 var client = new HttpClient(); | 251 var client = new HttpClient(); |
| 253 var connection = client.open(http_method, _host, _port, path); | 252 var connection = client.open(http_method, _host, _port, path); |
| 254 | 253 |
| 255 connection.onRequest = (r) { | 254 connection.onRequest = (r) { |
| 256 r.headers.add(HttpHeaders.ACCEPT, "application/json"); | 255 r.headers.add(HttpHeaders.ACCEPT, "application/json"); |
| 257 r.headers.add( | 256 r.headers.add( |
| 258 HttpHeaders.CONTENT_TYPE, 'application/json;charset=UTF-8'); | 257 HttpHeaders.CONTENT_TYPE, 'application/json;charset=UTF-8'); |
| 259 OutputStream s = r.outputStream; | 258 OutputStream s = r.outputStream; |
| 260 if (params != null && params is Map) { | 259 if (params != null && params is Map) { |
| 261 s.writeString(JSON.stringify(params)); | 260 s.writeString(json.stringify(params)); |
| 262 } | 261 } |
| 263 s.close(); | 262 s.close(); |
| 264 }; | 263 }; |
| 265 connection.onError = (e) { | 264 connection.onError = (e) { |
| 266 if (completer != null) { | 265 if (completer != null) { |
| 267 completer.completeException(new WebDriverError(-1, e)); | 266 completer.completeException(new WebDriverError(-1, e)); |
| 268 completer = null; | 267 completer = null; |
| 269 } | 268 } |
| 270 }; | 269 }; |
| 271 connection.followRedirects = false; | 270 connection.followRedirects = false; |
| 272 connection.onResponse = (r) { | 271 connection.onResponse = (r) { |
| 273 StringInputStream s = new StringInputStream(r.inputStream); | 272 StringInputStream s = new StringInputStream(r.inputStream); |
| 274 StringBuffer sbuf = new StringBuffer(); | 273 StringBuffer sbuf = new StringBuffer(); |
| 275 s.onData = () { | 274 s.onData = () { |
| 276 var data = s.read(); | 275 var data = s.read(); |
| 277 if (data != null) { | 276 if (data != null) { |
| 278 sbuf.add(data); | 277 sbuf.add(data); |
| 279 } | 278 } |
| 280 }; | 279 }; |
| 281 s.onClosed = () { | 280 s.onClosed = () { |
| 282 var value = null; | 281 var value = null; |
| 283 results = sbuf.toString().trim(); | 282 results = sbuf.toString().trim(); |
| 284 // For some reason we get a bunch of NULs on the end | 283 // For some reason we get a bunch of NULs on the end |
| 285 // of the text and the JSON parser blows up on these, so | 284 // of the text and the json.parse blows up on these, so |
| 286 // strip them. We have to do this the hard way as | 285 // strip them. We have to do this the hard way as |
| 287 // replaceAll('\0', '') does not work. | 286 // replaceAll('\0', '') does not work. |
| 288 // These NULs can be seen in the TCP packet, so it is not | 287 // These NULs can be seen in the TCP packet, so it is not |
| 289 // an issue with character encoding; it seems to be a bug | 288 // an issue with character encoding; it seems to be a bug |
| 290 // in WebDriver stack. | 289 // in WebDriver stack. |
| 291 for (var i = results.length; --i >= 0;) { | 290 for (var i = results.length; --i >= 0;) { |
| 292 var code = results.charCodeAt(i); | 291 var code = results.charCodeAt(i); |
| 293 if (code != 0) { | 292 if (code != 0) { |
| 294 results = results.substring(0, i+1); | 293 results = results.substring(0, i+1); |
| 295 break; | 294 break; |
| 296 } | 295 } |
| 297 } | 296 } |
| 298 if (successCodes.indexOf(r.statusCode) < 0) { | 297 if (successCodes.indexOf(r.statusCode) < 0) { |
| 299 throw 'Unexpected response ${r.statusCode}'; | 298 throw 'Unexpected response ${r.statusCode}'; |
| 300 } | 299 } |
| 301 if (status == 0 && results.length > 0) { | 300 if (status == 0 && results.length > 0) { |
| 302 // 4xx responses send plain text; others send JSON. | 301 // 4xx responses send plain text; others send JSON. |
| 303 if (r.statusCode < 400) { | 302 if (r.statusCode < 400) { |
| 304 results = JSON.parse(results); | 303 results = json.parse(results); |
| 305 status = results['status']; | 304 status = results['status']; |
| 306 } | 305 } |
| 307 if (results is Map && (results as Map).containsKey('value')) { | 306 if (results is Map && (results as Map).containsKey('value')) { |
| 308 value = results['value']; | 307 value = results['value']; |
| 309 } | 308 } |
| 310 if (value is Map && value.containsKey('message')) { | 309 if (value is Map && value.containsKey('message')) { |
| 311 message = value['message']; | 310 message = value['message']; |
| 312 } | 311 } |
| 313 } | 312 } |
| 314 if (status == 0) { | 313 if (status == 0) { |
| (...skipping 1042 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1357 * Get the log for a given log type. Log buffer is reset after each request. | 1356 * Get the log for a given log type. Log buffer is reset after each request. |
| 1358 * Each log entry is a [Map] with these fields: | 1357 * Each log entry is a [Map] with these fields: |
| 1359 * | 1358 * |
| 1360 * 'timestamp' (int) - The timestamp of the entry. | 1359 * 'timestamp' (int) - The timestamp of the entry. |
| 1361 * 'level' (String) - The log level of the entry, for example, "INFO". | 1360 * 'level' (String) - The log level of the entry, for example, "INFO". |
| 1362 * 'message' (String) - The log message. | 1361 * 'message' (String) - The log message. |
| 1363 */ | 1362 */ |
| 1364 Future<List<Map>> getLogs(String type) => | 1363 Future<List<Map>> getLogs(String type) => |
| 1365 _post('log', params: { 'type': type }); | 1364 _post('log', params: { 'type': type }); |
| 1366 } | 1365 } |
| OLD | NEW |