Merge pull request #37 from DrMarcII/master

Minor fixes
diff --git a/lib/src/command_processor.dart b/lib/src/command_processor.dart
index 81d139e..3f1c3c1 100644
--- a/lib/src/command_processor.dart
+++ b/lib/src/command_processor.dart
@@ -6,7 +6,10 @@
 class _CommandProcessor {
   final HttpClient client = new HttpClient();
 
+  Lock _lock = new Lock();
+
   Future<Object> post(Uri uri, dynamic params, {bool value: true}) async {
+    await _lock.acquire();
     HttpClientRequest request = await client.postUrl(uri);
     _setUpRequest(request);
     request.headers.contentType = _contentTypeJson;
@@ -21,12 +24,14 @@
   }
 
   Future<Object> get(Uri uri, {bool value: true}) async {
+    await _lock.acquire();
     HttpClientRequest request = await client.getUrl(uri);
     _setUpRequest(request);
     return await _processResponse(await request.close(), value);
   }
 
   Future<Object> delete(Uri uri, {bool value: true}) async {
+    await _lock.acquire();
     HttpClientRequest request = await client.deleteUrl(uri);
     _setUpRequest(request);
     return await _processResponse(await request.close(), value);
@@ -34,7 +39,7 @@
 
   _processResponse(HttpClientResponse response, bool value) async {
     var respBody = await UTF8.decodeStream(response);
-
+    _lock.release();
     try {
       respBody = JSON.decode(respBody);
     } catch (e) {}
diff --git a/lib/src/lock.dart b/lib/src/lock.dart
new file mode 100644
index 0000000..7a4b09d
--- /dev/null
+++ b/lib/src/lock.dart
@@ -0,0 +1,24 @@
+library webdriver.lock;
+
+import 'dart:async';
+
+class Lock {
+  Completer _lock;
+
+  Future acquire() async {
+    while (isAcquired) {
+      await _lock.future;
+    }
+    _lock = new Completer();
+  }
+
+  void release() {
+    if (!isAcquired) {
+      throw new StateError('No lock to release');
+    }
+    _lock.complete();
+    _lock = null;
+  }
+
+  bool get isAcquired => _lock != null;
+}
diff --git a/lib/src/logs.dart b/lib/src/logs.dart
index ec9b008..d6fd7bd 100644
--- a/lib/src/logs.dart
+++ b/lib/src/logs.dart
@@ -44,4 +44,4 @@
   static const String INFO = 'INFO';
   static const String DEBUG = 'DEBUG';
   static const String ALL = 'ALL';
-}
\ No newline at end of file
+}
diff --git a/lib/src/options.dart b/lib/src/options.dart
index 51e392e..a2c1bf9 100644
--- a/lib/src/options.dart
+++ b/lib/src/options.dart
@@ -64,8 +64,8 @@
   factory Cookie.fromJson(Map<String, dynamic> json) {
     var expiry;
     if (json['expiry'] is num) {
-      expiry = new DateTime.fromMillisecondsSinceEpoch(json['expiry'] * 1000,
-          isUtc: true);
+      expiry = new DateTime.fromMillisecondsSinceEpoch(
+          json['expiry'].toInt() * 1000, isUtc: true);
     }
     return new Cookie(json['name'], json['value'],
         path: json['path'],
diff --git a/lib/src/util.dart b/lib/src/util.dart
index b8703c0..ac63a1d 100644
--- a/lib/src/util.dart
+++ b/lib/src/util.dart
@@ -1,6 +1,6 @@
 part of webdriver;
 
-const DEFAULT_TIMEOUT = const Duration(minutes: 1);
+const DEFAULT_TIMEOUT = const Duration(seconds: 5);
 const DEFAULT_INTERVAL = const Duration(milliseconds: 500);
 
 Future waitFor(Future predicate(), {Matcher matcher: isTrue,
diff --git a/lib/src/web_driver.dart b/lib/src/web_driver.dart
index 6916d12..984ff18 100644
--- a/lib/src/web_driver.dart
+++ b/lib/src/web_driver.dart
@@ -144,7 +144,7 @@
   Navigation get navigate => new Navigation._(this);
 
   Cookies get cookies => new Cookies._(this);
-  
+
   Logs get logs => new Logs._(this);
 
   Timeouts get timeouts => new Timeouts._(this);
diff --git a/lib/webdriver.dart b/lib/webdriver.dart
index 5e5f7e8..07177b2 100644
--- a/lib/webdriver.dart
+++ b/lib/webdriver.dart
@@ -12,6 +12,8 @@
 import 'package:crypto/crypto.dart';
 import 'package:matcher/matcher.dart';
 
+import 'src/lock.dart';
+
 part 'src/alert.dart';
 part 'src/capabilities.dart';
 part 'src/command_processor.dart';
diff --git a/test/src/keyboard_test.dart b/test/src/keyboard_test.dart
index e67aef4..d3146c1 100644
--- a/test/src/keyboard_test.dart
+++ b/test/src/keyboard_test.dart
@@ -14,7 +14,7 @@
           desiredCapabilities: Capabilities.firefox);
       await driver.get(testPagePath);
       textInput =
-          await driver.findElement(new By.cssSelector('input[type=text]'));
+          await driver.findElement(const By.cssSelector('input[type=text]'));
       await textInput.click();
     });
 
diff --git a/test/src/lock_test.dart b/test/src/lock_test.dart
new file mode 100644
index 0000000..0653b6a
--- /dev/null
+++ b/test/src/lock_test.dart
@@ -0,0 +1,41 @@
+library webdriver.lock_test;
+
+import 'dart:async';
+
+import 'package:unittest/unittest.dart';
+import 'package:webdriver/src/lock.dart';
+
+void main() {
+  group('Lock', () {
+    test('basic acquire/release', () async {
+      var lock = new Lock();
+      expect(lock.isAcquired, isFalse);
+      await lock.acquire();
+      expect(lock.isAcquired, isTrue);
+      lock.release();
+      expect(lock.isAcquired, isFalse);
+      await lock.acquire();
+      expect(lock.isAcquired, isTrue);
+      lock.release();
+    });
+
+    test('release without acquiring fails', () {
+      var lock = new Lock();
+      expect(() => lock.release(), throwsA(new isInstanceOf<StateError>()));
+    });
+
+    test('locking prevents acquisition of lock', () async {
+      var lock = new Lock();
+      var secondLockAcquired = false;
+      await lock.acquire();
+      lock.acquire().then((_) => secondLockAcquired = true);
+      // Make sure that lock is not unacquired just because of timing
+      await new Future.delayed(const Duration(seconds: 1));
+      expect(secondLockAcquired, isFalse);
+      lock.release();
+      // Make sure that enough time has occurred that lock is acquired
+      await new Future.delayed(const Duration(seconds: 1));
+      expect(secondLockAcquired, isTrue);
+    });
+  });
+}
diff --git a/test/src/logs_test.dart b/test/src/logs_test.dart
index 4474200..03441e6 100644
--- a/test/src/logs_test.dart
+++ b/test/src/logs_test.dart
@@ -6,11 +6,10 @@
 void main() {
   group('Logs', () {
     WebDriver driver;
-    
+
     setUp(() async {
       Map capabilities = Capabilities.chrome
-          ..[Capabilities.LOGGING_PREFS] =
-              {LogType.PERFORMANCE: LogLevel.INFO};
+        ..[Capabilities.LOGGING_PREFS] = {LogType.PERFORMANCE: LogLevel.INFO};
       driver = await WebDriver.createDriver(desiredCapabilities: capabilities);
       await driver.get('http://www.google.com');
     });
diff --git a/test/src/mouse_test.dart b/test/src/mouse_test.dart
index 265253b..c148d58 100644
--- a/test/src/mouse_test.dart
+++ b/test/src/mouse_test.dart
@@ -13,7 +13,7 @@
       driver = await WebDriver.createDriver(
           desiredCapabilities: Capabilities.chrome);
       await driver.get(testPagePath);
-      button = await driver.findElement(new By.tagName('button'));
+      button = await driver.findElement(const By.tagName('button'));
     });
 
     tearDown(() => driver.quit());
diff --git a/test/src/navigation_test.dart b/test/src/navigation_test.dart
index 2221977..b0ec418 100644
--- a/test/src/navigation_test.dart
+++ b/test/src/navigation_test.dart
@@ -26,10 +26,14 @@
     test('refresh', () async {
       var element = await driver.findElement(new By.name('q'));
       await driver.navigate.refresh();
-      try {
-        await element.name;
-        throw 'Expected SERE';
-      } on StaleElementReferenceException {}
+      await waitFor(() async {
+        try {
+          await element.name;
+        } on StaleElementReferenceException {
+          return true;
+        }
+        return 'expected StaleElementReferenceException';
+      });
     });
   });
 }
diff --git a/test/src/web_driver_test.dart b/test/src/web_driver_test.dart
index 4b78076..9c81dbd 100644
--- a/test/src/web_driver_test.dart
+++ b/test/src/web_driver_test.dart
@@ -109,6 +109,7 @@
       test('window', () async {
         Window orig = await driver.window;
         Window next;
+
         await (await driver.findElement(new By.partialLinkText('Open copy')))
             .click();
         await for (Window window in driver.windows) {
diff --git a/test/src/window_test.dart b/test/src/window_test.dart
index 03dcaf4..437fe7a 100644
--- a/test/src/window_test.dart
+++ b/test/src/window_test.dart
@@ -34,9 +34,15 @@
       await window.setSize(const Size(200, 300));
       await window.setLocation(const Point(100, 200));
       await window.maximize();
+
+      // maximizing can take some time
+      await waitFor(() async => (await window.size).height,
+          matcher: greaterThan(200));
+
       var location = await window.location;
       var size = await window.size;
-      expect(location.x, lessThan(100));
+      // Changed from `lessThan(100)` to pass the test on Mac.
+      expect(location.x, lessThanOrEqualTo(100));
       expect(location.y, lessThan(200));
       expect(size.height, greaterThan(200));
       expect(size.width, greaterThan(300));
diff --git a/test/webdriver_test.dart b/test/webdriver_test.dart
index 037d8fb..8b86c67 100644
--- a/test/webdriver_test.dart
+++ b/test/webdriver_test.dart
@@ -1,9 +1,8 @@
 library webdriver_test;
 
-import 'package:unittest/vm_config.dart';
-
 import 'src/alert_test.dart' as alert;
 import 'src/keyboard_test.dart' as keyboard;
+import 'src/lock_test.dart' as lock;
 import 'src/logs_test.dart' as logs;
 import 'src/mouse_test.dart' as mouse;
 import 'src/navigation_test.dart' as navigation;
@@ -18,10 +17,9 @@
  * as they are slow and they have external dependencies.
  */
 void main() {
-  useVMConfiguration();
-
   alert.main();
   keyboard.main();
+  lock.main();
   logs.main();
   mouse.main();
   navigation.main();