Adds logic to automatically infer specification type during WebDriver creation. (#172)
* Adds automated spec inference ability during WebDriver creation.
* Adds ability to define spec during WebDriver creation. Sets defaults to W3C for FireFox and JSONWire for Chrome.
* Adds test for spec inference. Updates logic for reusing exisiting sessions for W3C spec.
* Add error messages.
* Updates spec inference test with different exception types.
diff --git a/lib/src/sync/json_wire_spec/exception.dart b/lib/src/sync/json_wire_spec/exception.dart
index 0c0b035..b1082f6 100644
--- a/lib/src/sync/json_wire_spec/exception.dart
+++ b/lib/src/sync/json_wire_spec/exception.dart
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-library webdriver.exception;
+library webdriver.json_exception;
import '../exception.dart';
diff --git a/lib/src/sync/spec_inference_response_processor.dart b/lib/src/sync/spec_inference_response_processor.dart
new file mode 100644
index 0000000..b5cf656
--- /dev/null
+++ b/lib/src/sync/spec_inference_response_processor.dart
@@ -0,0 +1,51 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import 'dart:convert' show JSON;
+
+import 'package:sync_http/sync_http.dart';
+import 'package:webdriver/sync_core.dart';
+
+/// Inferred spec and sessionId from a session creation request.
+class InferredResponse {
+ final String sessionId;
+
+ final WebDriverSpec spec;
+
+ InferredResponse(this.sessionId, this.spec);
+}
+
+/// Infers the spec during session creation.
+dynamic inferSessionResponseSpec(SyncHttpClientResponse response, bool _) {
+ Map responseBody;
+ try {
+ responseBody = JSON.decode(response.body);
+ } catch (e) {}
+
+ // TODO(staats): create more description error messages.
+ if (response.statusCode < 200 || response.statusCode > 299) {
+ throw 'Response code: ${response.statusCode}';
+ }
+
+ // JSON responses have multiple keys.
+ if (responseBody.keys.length > 1) {
+ return new InferredResponse(
+ responseBody['sessionId'], WebDriverSpec.JsonWire);
+ // W3C responses have only one key, value.
+ } else if (responseBody.keys.length == 1) {
+ return new InferredResponse(
+ responseBody['value']['sessionId'], WebDriverSpec.W3c);
+ }
+ throw 'Could not infer spec type; number of keys: ${responseBody.keys}';
+}
diff --git a/lib/src/sync/w3c_spec/exception.dart b/lib/src/sync/w3c_spec/exception.dart
index 8fee62c..6bf474e 100644
--- a/lib/src/sync/w3c_spec/exception.dart
+++ b/lib/src/sync/w3c_spec/exception.dart
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-library webdriver.exception;
+library webdriver.w3c_exception;
import '../exception.dart';
diff --git a/lib/sync_core.dart b/lib/sync_core.dart
index 45dd702..4024c45 100644
--- a/lib/sync_core.dart
+++ b/lib/sync_core.dart
@@ -20,6 +20,7 @@
import 'package:webdriver/src/sync/web_driver.dart' show WebDriver;
import 'package:webdriver/src/sync/command_processor.dart';
+import 'package:webdriver/src/sync/spec_inference_response_processor.dart';
import 'package:webdriver/src/sync/json_wire_spec/response_processor.dart';
import 'package:webdriver/src/sync/json_wire_spec/web_driver.dart' as jwire;
import 'package:webdriver/src/sync/w3c_spec/response_processor.dart';
@@ -79,7 +80,12 @@
return new w3c.W3cWebDriver(processor, uri, response['sessionId'],
new UnmodifiableMapView(response['value'] as Map<String, dynamic>));
case WebDriverSpec.Auto:
- throw 'Not yet supported!';
+ final response =
+ new SyncHttpCommandProcessor(processor: inferSessionResponseSpec)
+ .post(uri.resolve('session'), {'desiredCapabilities': desired},
+ value: true) as InferredResponse;
+ return fromExistingSession(response.sessionId,
+ uri: uri, spec: response.spec);
default:
throw 'Not yet supported!'; // Impossible.
}
@@ -102,12 +108,10 @@
case WebDriverSpec.W3c:
final processor =
new SyncHttpCommandProcessor(processor: processW3cResponse);
- final response = processor.get(uri.resolve('session/$sessionId'))
- as Map<String, dynamic>;
return new w3c.W3cWebDriver(
- processor, uri, sessionId, new UnmodifiableMapView(response));
+ processor, uri, sessionId, new Map<String, dynamic>());
case WebDriverSpec.Auto:
- throw 'Not yet supported!';
+ throw 'Not supported!';
default:
throw 'Not yet supported!'; // Impossible.
}
diff --git a/test/sync/spec_inference_test.dart b/test/sync/spec_inference_test.dart
new file mode 100644
index 0000000..4f7c608
--- /dev/null
+++ b/test/sync/spec_inference_test.dart
@@ -0,0 +1,64 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+@TestOn("vm")
+library webdriver.spec_inference_test;
+
+import 'package:test/test.dart';
+import 'package:webdriver/src/sync/json_wire_spec/exception.dart' as json;
+import 'package:webdriver/src/sync/w3c_spec/exception.dart' as w3c;
+import 'package:webdriver/sync_core.dart';
+
+import 'sync_io_config.dart' as config;
+
+void main() {
+ group('Spec inference', () {
+ WebDriver driver;
+
+ setUp(() {});
+
+ tearDown(() {
+ if (driver != null) {
+ driver.quit();
+ }
+ driver = null;
+ });
+
+ test('chrome works', () {
+ driver = config.createChromeTestDriver(spec: WebDriverSpec.Auto);
+ driver.get(config.testPagePath);
+ final button = driver.findElement(const By.tagName('button'));
+ try {
+ button.findElement(const By.tagName('tr'));
+ throw 'Expected NoSuchElementException';
+ } catch(e) {
+ expect(e, new isInstanceOf<json.NoSuchElementException>());
+ expect(e.toString(), contains('Unable to locate element'));
+ }
+ });
+
+ test('firefox work', () {
+ driver = config.createFirefoxTestDriver(spec: WebDriverSpec.Auto);
+ driver.get(config.testPagePath);
+ final button = driver.findElement(const By.tagName('button'));
+ try {
+ button.findElement(const By.tagName('tr'));
+ throw 'Expected W3cWebDriverException';
+ } catch(e) {
+ expect(e, new isInstanceOf<w3c.W3cWebDriverException>());
+ expect(e.toString(), contains('Unable to locate element'));
+ }
+ });
+ }, timeout: new Timeout(new Duration(minutes: 2)));
+}
diff --git a/test/sync/sync_io_config.dart b/test/sync/sync_io_config.dart
index 8e2e9e9..85a3797 100644
--- a/test/sync/sync_io_config.dart
+++ b/test/sync/sync_io_config.dart
@@ -29,18 +29,20 @@
final Uri _defaultFirefoxUri = Uri.parse('http://127.0.0.1:4445/');
WebDriver createFirefoxTestDriver(
- {Map<String, dynamic> additionalCapabilities}) {
+ {Map<String, dynamic> additionalCapabilities,
+ WebDriverSpec spec: WebDriverSpec.W3c}) {
final capabilities = Capabilities.firefox;
if (additionalCapabilities != null) {
capabilities.addAll(additionalCapabilities);
}
return createDriver(
- uri: _defaultFirefoxUri, desired: capabilities, spec: WebDriverSpec.W3c);
+ uri: _defaultFirefoxUri, desired: capabilities, spec: spec);
}
WebDriver createChromeTestDriver(
- {Map<String, dynamic> additionalCapabilities}) {
+ {Map<String, dynamic> additionalCapabilities,
+ WebDriverSpec spec: WebDriverSpec.JsonWire}) {
var capabilities = Capabilities.chrome;
Map env = Platform.environment;
@@ -62,5 +64,6 @@
capabilities.addAll(additionalCapabilities);
}
- return createDriver(uri: _defaultChromeUri, desired: additionalCapabilities);
+ return createDriver(
+ uri: _defaultChromeUri, desired: additionalCapabilities, spec: spec);
}