Merge pull request #73 from DrMarcII/master
Add support/forwarder.dart
diff --git a/lib/html.dart b/lib/html.dart
index f5f9e6e..56ce288 100644
--- a/lib/html.dart
+++ b/lib/html.dart
@@ -18,7 +18,7 @@
import 'dart:convert' show JSON, UTF8;
import 'dart:html' show HttpRequest, ProgressEvent;
-import 'package:webdriver/async_helpers.dart' show Lock;
+import 'package:webdriver/support/async.dart' show Lock;
import 'package:webdriver/core.dart' as core
show createDriver, fromExistingSession, WebDriver;
import 'package:webdriver/src/command_processor.dart' show CommandProcessor;
diff --git a/lib/io.dart b/lib/io.dart
index d20dceb..a5fa975 100644
--- a/lib/io.dart
+++ b/lib/io.dart
@@ -24,7 +24,7 @@
HttpClientResponse,
HttpHeaders;
-import 'package:webdriver/async_helpers.dart' show Lock;
+import 'package:webdriver/support/async.dart' show Lock;
import 'package:webdriver/core.dart' as core
show createDriver, fromExistingSession, WebDriver;
import 'package:webdriver/src/command_processor.dart' show CommandProcessor;
diff --git a/lib/src/web_driver.dart b/lib/src/web_driver.dart
index fc64ed1..ffe26e2 100644
--- a/lib/src/web_driver.dart
+++ b/lib/src/web_driver.dart
@@ -178,13 +178,20 @@
}
Future postRequest(String command, [params]) =>
- _commandProcessor.post(_prefix.resolve(command), params);
+ _commandProcessor.post(_resolve(command), params);
- Future getRequest(String command) =>
- _commandProcessor.get(_prefix.resolve(command));
+ Future getRequest(String command) => _commandProcessor.get(_resolve(command));
Future deleteRequest(String command) =>
- _commandProcessor.delete(_prefix.resolve(command));
+ _commandProcessor.delete(_resolve(command));
+
+ Uri _resolve(String command) {
+ var uri = _prefix.resolve(command);
+ if (uri.path.endsWith('/')) {
+ uri = uri.replace(path: uri.path.substring(0, uri.path.length - 1));
+ }
+ return uri;
+ }
@override
WebDriver get driver => this;
diff --git a/lib/async_helpers.dart b/lib/support/async.dart
similarity index 98%
rename from lib/async_helpers.dart
rename to lib/support/async.dart
index 8b1d311..3f021af 100644
--- a/lib/async_helpers.dart
+++ b/lib/support/async.dart
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-library webdriver.async_helpers;
+library webdriver.support.async;
import 'dart:async' show Completer, Future;
diff --git a/lib/support/forwarder.dart b/lib/support/forwarder.dart
new file mode 100644
index 0000000..651ec8b
--- /dev/null
+++ b/lib/support/forwarder.dart
@@ -0,0 +1,214 @@
+// Copyright 2015 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.
+
+library webdriver.support.forwarder;
+
+import 'dart:async' show Future, StreamConsumer;
+import 'dart:convert' show JSON, UTF8;
+import 'dart:io' show ContentType, Directory, File, HttpRequest, HttpStatus;
+
+import 'package:path/path.dart' as path;
+import 'package:webdriver/core.dart'
+ show By, WebDriver, WebDriverException, WebElement;
+
+final _contentTypeJson =
+ new ContentType('application', 'json', charset: 'utf-8');
+
+/// Attribute on elements used to locate them on passed WebDriver commands.
+const wdElementIdAttribute = 'wd-element-id';
+
+/// [WebDriverForwarder] accepts [HttpRequest]s corresponding to a variation on
+/// the WebDriver wire protocol and forwards them to a WebDriver instance.
+///
+/// The primary difference between this and the standard wire protocol is in
+/// the use of WebElement ids. When you need to refer to an element in a request
+/// (URI or JSON body), then you should add an 'wd-element-id' attribute to the
+/// corresponding element with a unique identifier, and use that identifier as
+/// the element id for that element. This class will then search for the
+/// corresponding element and in the document and will substitute an actual
+/// WebElement id for the given identifier in the request.
+///
+/// This forwarder supports two additional commands that control how it searches
+/// for elements:
+/// POST '/enabledeep': enables searching through all Shadow DOMs in the
+/// document for the corresponding element (but will fail on browsers that
+/// don't support the '/deep/' css selector combinator).
+/// POST '/disabledeep': disables searching in Shadow DOMs of the document.
+///
+/// This forwarder also supports two additional commands for grabbing the
+/// browser contents and saving it to the file system.
+/// POST '/screenshot': takes a 'file' arg and will capture a screenshot
+/// of the browser and save it to the specified file name in [outputDir].
+/// POST '/source': takes a 'file' arg and will capture the current page's
+/// source and save it to the specified file name in [outputDir].
+///
+/// See https://code.google.com/p/selenium/wiki/JsonWireProtocol for
+/// documentation of other commands.
+class WebDriverForwarder {
+ /// [WebDriver] instance to forward commands to.
+ final WebDriver driver;
+ /// Path prefix that all forwarded commands will have.
+ final Pattern prefix;
+ /// Directory to save screenshots and page source to.
+ final Directory outputDir;
+ /// Search for elements in all shadow doms of the current document.
+ bool useDeep;
+
+ WebDriverForwarder(this.driver,
+ {this.prefix: '/webdriver', Directory outputDir, this.useDeep: false})
+ : this.outputDir = outputDir == null
+ ? Directory.systemTemp.createTempSync()
+ : outputDir;
+
+ /// Forward [request] to [driver] and respond to the request with the returned
+ /// value or any thrown exceptions.
+ Future forward(HttpRequest request) async {
+ try {
+ if (!request.uri.path.startsWith(prefix)) {
+ request.response.statusCode = HttpStatus.NOT_FOUND;
+ return;
+ }
+ request.response.statusCode = HttpStatus.OK;
+ request.response.headers.contentType = _contentTypeJson;
+
+ var endpoint = request.uri.path.replaceFirst(prefix, '');
+ if (endpoint.startsWith('/')) {
+ endpoint = endpoint.substring(1);
+ }
+ var params;
+ if (request.method == 'POST') {
+ String requestBody = await UTF8.decodeStream(request);
+ if (requestBody != null && requestBody.isNotEmpty) {
+ params = JSON.decode(requestBody);
+ }
+ }
+ var value = await _forward(request.method, endpoint, params);
+ request.response
+ .add(UTF8.encode(JSON.encode({'status': 0, 'value': value})));
+ } on WebDriverException catch (e) {
+ request.response.add(UTF8.encode(JSON
+ .encode({'status': e.statusCode, 'value': {'message': e.message}})));
+ } catch (e) {
+ request.response.add(UTF8.encode(
+ JSON.encode({'status': 13, 'value': {'message': e.toString()}})));
+ } finally {
+ await request.response.close();
+ }
+ }
+
+ Future _forward(String method, String endpoint,
+ [Map<String, dynamic> params]) async {
+ List<String> endpointTokens = path.split(endpoint);
+ if (endpointTokens.isEmpty) {
+ endpointTokens = [''];
+ }
+ switch (endpointTokens[0]) {
+ case 'enabledeep':
+ // turn on Shadow DOM support, don't forward
+ useDeep = true;
+ return null;
+ case 'disabledeep':
+ // turn off Shadow DOM support, don't forward
+ useDeep = false;
+ return null;
+ case 'screenshot':
+ if (method == 'POST') {
+ // take a screenshot and save to file system
+ var file =
+ new File(path.join(outputDir.path, params['file'])).openWrite();
+ await driver.captureScreenshot().pipe(file as StreamConsumer<int>);
+ return null;
+ }
+ break;
+ case 'source':
+ if (method == 'POST') {
+ // grab page source and save to file system
+ await new File(path.join(outputDir.path, params['file']))
+ .writeAsString(await driver.pageSource);
+ return null;
+ }
+ break;
+ case 'element':
+ // process endpoints of the form /element/[id]/...
+ if (endpointTokens.length >= 2) {
+ endpointTokens[1] = await _findElement(endpointTokens[1]);
+ }
+ // process endpoint /element/[id]/equals/[id]
+ if (endpointTokens.length == 4 && endpointTokens[2] == 'equals') {
+ endpointTokens[3] = await _findElement(endpointTokens[3]);
+ }
+ break;
+ case 'touch':
+ case 'moveto':
+ // several /touch/... endpoints and the /moveto endpoint have an
+ // optional 'element' param with a WebElement id value
+ if (params['element'] != null) {
+ params = new Map.from(params);
+ params['element'] = await _findElement(params['element']);
+ }
+ break;
+ case 'execute':
+ case 'execute_async':
+ // /execute and /execute_async allow arbitrary JSON objects with
+ // embedded WebElememt ids.
+ params = await _deepCopy(params);
+ break;
+ }
+
+ switch (method) {
+ case 'GET':
+ return await driver.getRequest(path.joinAll(endpointTokens));
+ case 'DELETE':
+ return await driver.deleteRequest(path.joinAll(endpointTokens));
+ case 'POST':
+ return await driver.postRequest(path.joinAll(endpointTokens), params);
+ default:
+ throw 'unsupported method $method';
+ }
+ }
+
+ Future<String> _findElement(String id) async {
+ var selector = "[$wdElementIdAttribute='$id']";
+ if (useDeep) {
+ selector = '* /deep/ $selector';
+ }
+ var elements =
+ await driver.findElements(new By.cssSelector(selector)).toList();
+ return elements.single.id;
+ }
+
+ dynamic _deepCopy(dynamic source) async {
+ if (source is Map) {
+ var copy = {};
+
+ for (var key in source.keys) {
+ var value = source[key];
+ if (key == 'ELEMENT') {
+ copy['ELEMENT'] = await _findElement(value);
+ } else {
+ copy[await _deepCopy(key)] = await _deepCopy(value);
+ }
+ }
+ return copy;
+ } else if (source is Iterable) {
+ var copy = [];
+ for (var value in source) {
+ copy.add(await _deepCopy(value));
+ }
+ return copy;
+ } else {
+ return source;
+ }
+ }
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index fd8dba8..4c661d8 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: webdriver
-version: 0.10.0-pre.7
+version: 0.10.0-pre.8
author: Marc Fisher II <fisherii@google.com>
description: >
Provides WebDriver bindings for Dart. These use the WebDriver JSON interface,
diff --git a/test/frame.html b/test/frame.html
index 30569eb..f1c7f09 100644
--- a/test/frame.html
+++ b/test/frame.html
@@ -17,11 +17,11 @@
-->
<html>
- <head>
+<head>
<title>frame</title>
- </head>
+</head>
- <body>
- <p id="text">this is a frame</p>
- </body>
+<body>
+<p id="text">this is a frame</p>
+</body>
</html>
diff --git a/test/io_config.dart b/test/io_config.dart
new file mode 100644
index 0000000..596d75b
--- /dev/null
+++ b/test/io_config.dart
@@ -0,0 +1,58 @@
+// Copyright 2015 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.
+
+library webdriver.io_test;
+
+import 'dart:io' show FileSystemEntity, Platform;
+
+import 'package:path/path.dart' as path;
+import 'package:webdriver/io.dart' show WebDriver, Capabilities, createDriver;
+
+import 'test_util.dart' as test_util;
+
+void config() {
+ test_util.runningOnTravis = Platform.environment['TRAVIS'] == 'true';
+ test_util.createTestDriver = ({Map additionalCapabilities}) {
+ Map capabilities = Capabilities.chrome;
+ Map env = Platform.environment;
+
+ Map chromeOptions = {};
+
+ if (env['CHROMEDRIVER_BINARY'] != null) {
+ chromeOptions['binary'] = env['CHROMEDRIVER_BINARY'];
+ }
+
+ if (env['CHROMEDRIVER_ARGS'] != null) {
+ chromeOptions['args'] = env['CHROMEDRIVER_ARGS'].split(' ');
+ }
+
+ if (chromeOptions.isNotEmpty) {
+ capabilities['chromeOptions'] = chromeOptions;
+ }
+
+ if (additionalCapabilities != null) {
+ capabilities.addAll(additionalCapabilities);
+ }
+
+ return createDriver(desired: capabilities);
+ };
+
+ var testPagePath = path.join(path.current, 'test', 'test_page.html');
+ testPagePath = path.absolute(testPagePath);
+ if (!FileSystemEntity.isFileSync(testPagePath)) {
+ throw new Exception('Could not find the test file at "$testPagePath".'
+ ' Make sure you are running tests from the root of the project.');
+ }
+ test_util.testPagePath = path.toUri(testPagePath).toString();
+}
diff --git a/test/io_test.dart b/test/io_test.dart
index 68feb35..62d2768 100644
--- a/test/io_test.dart
+++ b/test/io_test.dart
@@ -15,12 +15,7 @@
@TestOn("vm")
library webdriver.io_test;
-import 'dart:io' show FileSystemEntity, Platform;
-
-import 'package:path/path.dart' as path;
import 'package:test/test.dart';
-import 'package:webdriver/io.dart'
- show WebDriver, Capabilities, createDriver, fromExistingSession;
import 'src/alert.dart' as alert;
import 'src/keyboard.dart' as keyboard;
@@ -33,64 +28,10 @@
import 'src/web_element.dart' as web_element;
import 'src/window.dart' as window;
-import 'test_util.dart' as test_util;
+import 'io_config.dart' as config;
void main() {
- test_util.runningOnTravis = Platform.environment['TRAVIS'] == 'true';
- test_util.createTestDriver = ({Map additionalCapabilities}) {
- Map capabilities = Capabilities.chrome;
- Map env = Platform.environment;
-
- Map chromeOptions = {};
-
- if (env['CHROMEDRIVER_BINARY'] != null) {
- chromeOptions['binary'] = env['CHROMEDRIVER_BINARY'];
- }
-
- if (env['CHROMEDRIVER_ARGS'] != null) {
- chromeOptions['args'] = env['CHROMEDRIVER_ARGS'].split(' ');
- }
-
- if (chromeOptions.isNotEmpty) {
- capabilities['chromeOptions'] = chromeOptions;
- }
-
- if (additionalCapabilities != null) {
- capabilities.addAll(additionalCapabilities);
- }
-
- return createDriver(desired: capabilities);
- };
-
- var testPagePath = path.join(path.current, 'test', 'test_page.html');
- testPagePath = path.absolute(testPagePath);
- if (!FileSystemEntity.isFileSync(testPagePath)) {
- throw new Exception('Could not find the test file at "$testPagePath".'
- ' Make sure you are running tests from the root of the project.');
- }
- test_util.testPagePath = path.toUri(testPagePath).toString();
-
- group('io-specific tests', () {
- WebDriver driver;
- setUp(() async {
- driver = await test_util.createTestDriver();
- await driver.get(test_util.testPagePath);
- });
-
- tearDown(() => driver.quit());
-
- test('fromExistingSession', () async {
- WebDriver newDriver =
- await fromExistingSession(driver.id, uri: driver.uri);
- expect(newDriver.capabilities, driver.capabilities);
- var url = await newDriver.currentUrl;
- expect(url, startsWith('file:'));
- expect(url, endsWith('test_page.html'));
- await newDriver.get('http://www.google.com/ncr');
- url = await driver.currentUrl;
- expect(url, contains('www.google.com'));
- });
- });
+ config.config();
alert.runTests();
keyboard.runTests();
diff --git a/test/src/navigation.dart b/test/src/navigation.dart
index 3ab0ff7..388e843 100644
--- a/test/src/navigation.dart
+++ b/test/src/navigation.dart
@@ -15,7 +15,7 @@
library webdriver.navigation_test;
import 'package:test/test.dart';
-import 'package:webdriver/async_helpers.dart';
+import 'package:webdriver/support/async.dart';
import 'package:webdriver/core.dart';
import '../test_util.dart';
diff --git a/test/src/window.dart b/test/src/window.dart
index 5b0c94a..0b60fe0 100644
--- a/test/src/window.dart
+++ b/test/src/window.dart
@@ -17,7 +17,7 @@
import 'dart:math' show Point, Rectangle;
import 'package:test/test.dart';
-import 'package:webdriver/async_helpers.dart';
+import 'package:webdriver/support/async.dart';
import 'package:webdriver/core.dart';
import '../test_util.dart';
diff --git a/test/async_helpers_test.dart b/test/support/async_test.dart
similarity index 97%
rename from test/async_helpers_test.dart
rename to test/support/async_test.dart
index 21c8239..b33a858 100644
--- a/test/async_helpers_test.dart
+++ b/test/support/async_test.dart
@@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-library webdriver.async_helpers_test;
+library webdriver.support.async_test;
import 'dart:async' show Future;
import 'package:test/test.dart';
-import 'package:webdriver/async_helpers.dart';
+import 'package:webdriver/support/async.dart';
void main() {
group('Lock', () {
diff --git a/test/support/forwarder_test.dart b/test/support/forwarder_test.dart
new file mode 100644
index 0000000..a6afbeb
--- /dev/null
+++ b/test/support/forwarder_test.dart
@@ -0,0 +1,157 @@
+// Copyright 2015 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.support.forwarder_test;
+
+import 'dart:io';
+
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+import 'package:webdriver/io.dart';
+import 'package:webdriver/support/forwarder.dart';
+
+import '../io_config.dart' as config;
+import '../test_util.dart' as test_util;
+
+const buttonClicked = 'Button clicked';
+const buttonNotClicked = 'Button not clicked';
+
+void main() {
+ config.config();
+
+ group('WebDriverForwarder', () {
+ WebDriver driver;
+ WebDriverForwarder forwarder;
+ HttpServer server;
+ WebDriver forwardedDriver;
+ Uri address;
+
+ setUp(() async {
+ driver = await test_util.createTestDriver();
+ ;
+ forwarder =
+ new WebDriverForwarder(driver, prefix: '/webdriver/session/1');
+
+ server = await HttpServer.bind(InternetAddress.ANY_IP_V4, 0);
+ server.listen((request) {
+ if (request.uri.path.startsWith('/webdriver')) {
+ forwarder.forward(request);
+ } else if (request.method == 'GET' &&
+ request.uri.path.endsWith('test_page.html')) {
+ File file = new File(
+ path.join('test', 'support', 'forwarder_test_page.html'));
+ request.response
+ ..statusCode = HttpStatus.OK
+ ..headers.set('Content-type', 'text/html');
+ file.openRead().pipe(request.response);
+ } else {
+ request.response
+ ..statusCode = HttpStatus.NOT_FOUND
+ ..close();
+ }
+ });
+ address = new Uri.http('localhost:${server.port}', '/webdriver/');
+ forwardedDriver = await fromExistingSession('1', uri: address);
+
+ await forwardedDriver.get(address.resolve('/test_page.html'));
+ });
+
+ tearDown(() async {
+ try {
+ await forwardedDriver.quit();
+ } catch (e) {
+ print('Ignored error quitting forwardedDriver: $e');
+ }
+ try {
+ await server.close(force: true);
+ } catch (e) {
+ print('Ignored error quitting server: $e');
+ }
+ try {
+ await driver.quit();
+ } catch (e) {
+ print('Ignored error quitting driver: $e');
+ }
+ });
+
+ test('get url', () async {
+ expect(await forwardedDriver.currentUrl, endsWith('test_page.html'));
+ });
+
+ test('click button', () async {
+ expect(await forwardedDriver.getRequest('element/div/text'),
+ buttonNotClicked);
+
+ await forwardedDriver.postRequest('element/button/click', {'button': 0});
+ expect(
+ await forwardedDriver.getRequest('element/div/text'), buttonClicked);
+ });
+
+ test('moveto/click', () async {
+ expect(await forwardedDriver.getRequest('element/div/text'),
+ buttonNotClicked);
+
+ await forwardedDriver.postRequest('moveto', {'element': 'button'});
+ await forwardedDriver.mouse.click();
+
+ expect(
+ await forwardedDriver.getRequest('element/div/text'), buttonClicked);
+ });
+
+ test('execute_script', () async {
+ expect(await forwardedDriver.getRequest('element/div/text'),
+ buttonNotClicked);
+
+ await forwardedDriver.execute(
+ 'arguments[0].el.click();', [{'el': {'ELEMENT': 'button'}}]);
+
+ expect(
+ await forwardedDriver.getRequest('element/div/text'), buttonClicked);
+ });
+
+ test('element equals', () async {
+ expect(
+ await forwardedDriver.getRequest('element/div/equals/div'), isTrue);
+ expect(await forwardedDriver.getRequest('element/div/equals/button'),
+ isFalse);
+ });
+
+ // TODO(DrMarcII) add test that actually uses shadow dom
+ test('enable/disable deep', () async {
+ await forwardedDriver.postRequest('disabledeep');
+
+ expect(await forwardedDriver.getRequest('element/div/text'),
+ buttonNotClicked);
+
+ await forwardedDriver.postRequest('element/button/click', {'button': 0});
+ expect(
+ await forwardedDriver.getRequest('element/div/text'), buttonClicked);
+
+ await forwardedDriver.postRequest('enabledeep');
+ await forwardedDriver.navigate.refresh();
+
+ expect(await forwardedDriver.getRequest('element/div/text'),
+ buttonNotClicked);
+
+ await forwardedDriver.postRequest('element/button/click', {'button': 0});
+ expect(
+ await forwardedDriver.getRequest('element/div/text'), buttonClicked);
+ });
+
+ test('window close', () async {
+ await forwardedDriver.close();
+ });
+ });
+}
diff --git a/test/support/forwarder_test_page.html b/test/support/forwarder_test_page.html
new file mode 100644
index 0000000..0991503
--- /dev/null
+++ b/test/support/forwarder_test_page.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+
+<!--
+Copyright 2015 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.
+-->
+
+<html>
+<head lang="en">
+ <meta charset="UTF-8">
+ <title></title>
+</head>
+<body>
+
+<input type="button" wd-element-id="button" onclick="buttonClicked()" value="button">
+
+<div wd-element-id="div">Button not clicked</div>
+
+<script>
+ function buttonClicked() {
+ document.querySelector('[wd-element-id="div"]').textContent = 'Button clicked';
+ }
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/test/test_page.html b/test/test_page.html
index ba9e7e7..ec05a7c 100644
--- a/test/test_page.html
+++ b/test/test_page.html
@@ -17,42 +17,43 @@
-->
<html>
- <head>
+<head>
<title>test_page</title>
<script>
- function promptForText() {
- var val = prompt('button clicked');
- if (val == null) {
- document.getElementById('settable').textContent = 'dismissed';
- } else {
- document.getElementById('settable').textContent = 'accepted ' + val;
+ function promptForText() {
+ var val = prompt('button clicked');
+ if (val == null) {
+ document.getElementById('settable').textContent = 'dismissed';
+ } else {
+ document.getElementById('settable').textContent = 'accepted ' + val;
+ }
}
- }
</script>
- </head>
+</head>
- <body>
- <table id='table1' non-standard='a non standard attr'>
- <tr>
+<body>
+<table id='table1' non-standard='a non standard attr'>
+ <tr>
<td>r1c1</td>
<td>r1c2</td>
- </tr>
- <tr>
+ </tr>
+ <tr>
<td>r2c1</td>
<td>r2c2</td>
- </tr>
- </table>
- <button onclick='promptForText();'>button</button>
- <form onsubmit='alert("form submitted")'>
- <input type='text' />
- <input type='checkbox' />
- <input type='password' disabled />
- </form>
- <div id='div' style='display: none; background-color: red'>
- some not displayed text</div>
- <a id='settable' href="test_page.html" target="_new">
- Open copy in other window</a>
- <br />
- <iframe src="frame.html" name="frame" width="100%" />
- </body>
+ </tr>
+</table>
+<button onclick='promptForText();'>button</button>
+<form onsubmit='alert("form submitted")'>
+ <input type='text'/>
+ <input type='checkbox'/>
+ <input type='password' disabled/>
+</form>
+<div id='div' style='display: none; background-color: red'>
+ some not displayed text
+</div>
+<a id='settable' href="test_page.html" target="_new">
+ Open copy in other window</a>
+<br/>
+<iframe src="frame.html" name="frame" width="100%"/>
+</body>
</html>
diff --git a/tool/travis.sh b/tool/travis.sh
index 1f41e17..c427b2e 100755
--- a/tool/travis.sh
+++ b/tool/travis.sh
@@ -18,15 +18,8 @@
set -e
# Verify that the libraries are error free.
-dartanalyzer --fatal-warnings \
- lib/async_helpers.dart \
- lib/core.dart \
- lib/html.dart \
- lib/io.dart \
- test/async_helpers_test.dart \
- test/html_test.dart \
- test/io_test.dart
-
+grep -Rl --include "*.dart" --exclude-dir="packages" '^library .*;$' lib/ test/ | \
+ xargs dartanalyzer --fatal-warnings
# Start chromedriver.
chromedriver --port=4444 --url-base=wd/hub &
@@ -35,4 +28,3 @@
# TODO(DrMarcII) enable running tests in browser when chrome setuid problem
# is fixed on travis.
pub run test -r expanded -p vm
-