Skip to content
Snippets Groups Projects
Commit c5e65775 authored by Natalie Weizenbaum's avatar Natalie Weizenbaum
Browse files

Add BrowserManager and IframeTest for communicating with browser tests.

See #5

R=kevmoo@google.com

Review URL: https://codereview.chromium.org//971103002
parent 230c987a
No related branches found
No related tags found
No related merge requests found
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library unittest.runner.browser.browser_manager;
import 'dart:async';
import 'dart:convert';
import 'package:http_parser/http_parser.dart';
import '../../backend/suite.dart';
import '../../util/multi_channel.dart';
import '../../util/remote_exception.dart';
import '../../utils.dart';
import '../load_exception.dart';
import 'iframe_test.dart';
/// A class that manages the connection to a single running browser.
///
/// This is in charge of telling the browser which test suites to load and
/// converting its responses into [Suite] objects.
class BrowserManager {
/// The channel used to communicate with the browser.
///
/// This is connected to a page running `static/host.dart`.
final MultiChannel _channel;
/// Creates a new BrowserManager that communicates with a browser over
/// [webSocket].
BrowserManager(CompatibleWebSocket webSocket)
: _channel = new MultiChannel(
webSocket.map(JSON.decode),
mapSink(webSocket, JSON.encode));
/// Tells the browser the load a test suite from the URL [url].
///
/// [url] should be an HTML page with a reference to the JS-compiled test
/// suite. [path] is the path of the original test suite file, which is used
/// for reporting.
Future<Suite> loadSuite(String path, Uri url) {
var suiteChannel = _channel.virtualChannel();
_channel.sink.add({
"command": "loadSuite",
"url": url.toString(),
"channel": suiteChannel.id
});
// Create a nested MultiChannel because the iframe will be using a channel
// wrapped within the host's channel.
suiteChannel = new MultiChannel(suiteChannel.stream, suiteChannel.sink);
return suiteChannel.stream.first.then((response) {
if (response["type"] == "loadException") {
return new Future.error(new LoadException(path, response["message"]));
} else if (response["type"] == "error") {
var asyncError = RemoteException.deserialize(response["error"]);
return new Future.error(
new LoadException(path, asyncError.error),
asyncError.stackTrace);
}
return new Suite(path, response["tests"].map((test) {
var testChannel = suiteChannel.virtualChannel(test['channel']);
return new IframeTest(test['name'], testChannel);
}));
});
}
}
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library unittest.runner.browser.iframe_test;
import '../../backend/live_test.dart';
import '../../backend/live_test_controller.dart';
import '../../backend/state.dart';
import '../../backend/suite.dart';
import '../../backend/test.dart';
import '../../util/multi_channel.dart';
import '../../util/remote_exception.dart';
/// A test in a running iframe.
class IframeTest implements Test {
final String name;
/// The channel used to communicate with the test's [IframeListener].
final MultiChannel _channel;
IframeTest(this.name, this._channel);
LiveTest load(Suite suite) {
var controller;
controller = new LiveTestController(suite, this, () {
controller.setState(const State(Status.running, Result.success));
var testChannel = _channel.virtualChannel();
_channel.sink.add({
'command': 'run',
'channel': testChannel.id
});
testChannel.stream.listen((message) {
if (message['type'] == 'error') {
var asyncError = RemoteException.deserialize(message['error']);
controller.addError(asyncError.error, asyncError.stackTrace);
} else if (message['type'] == 'state-change') {
controller.setState(
new State(
new Status.parse(message['status']),
new Result.parse(message['result'])));
} else {
assert(message['type'] == 'complete');
controller.completer.complete();
}
});
});
return controller.liveTest;
}
}
......@@ -64,6 +64,16 @@ List flatten(Iterable nested) {
return result;
}
/// Returns a sink that maps events sent to [original] using [fn].
StreamSink mapSink(StreamSink original, fn(event)) {
var controller = new StreamController(sync: true);
controller.stream.listen(
(event) => original.add(fn(event)),
onError: (error, stackTrace) => original.addError(error, stackTrace),
onDone: () => original.close());
return controller.sink;
}
/// Truncates [text] to fit within [maxLength].
///
/// This will try to truncate along word boundaries and preserve words both at
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment