Skip to content

Commit

Permalink
Send a MessagePort to host on frame startup (#2072)
Browse files Browse the repository at this point in the history
Towards #2065

All host implementations are updated to allow either the legacy format,
or this new format.

Simplify the communication and avoid a listener on the frame window
message events. Upon startup replace the `{'ready': true}` message with
a `'port'` message and the `MessagePort` for a channel created on the
frame side. Omit the manual 'href' field, no host implementations would
read it.
  • Loading branch information
natebosch authored Aug 9, 2023
1 parent ae2ab1e commit 9b1828f
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 38 deletions.
5 changes: 5 additions & 0 deletions pkgs/test/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 1.24.7-wip

* Simplify the initialization of the per-suite message channel within browser
tests. See https://github.com/dart-lang/test/issues/2065

## 1.24.6

* Fix communication failures between minified test apps and the non-minified
Expand Down
50 changes: 13 additions & 37 deletions pkgs/test/lib/src/runner/browser/post_message_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,23 @@ import 'package:stream_channel/stream_channel.dart';

import 'dom.dart' as dom;

/// Constructs a [StreamChannel] wrapping [MessageChannel] communication with
/// the host page.
/// Constructs a [StreamChannel] wrapping a new [MessageChannel] communicating
/// with the host page.
///
/// Sends a [MessagePort] to the host page for the channel.
StreamChannel<Object?> postMessageChannel() {
var controller = StreamChannelController<Object?>(sync: true);

// Listen for a message from the host that transfers a message port, then
// cancel the subscription. This is important to prevent multiple
// subscriptions if the test is ever hot restarted.
late final dom.Subscription subscription;
subscription =
dom.Subscription(dom.window, 'message', allowInterop((dom.Event event) {
// A message on the Window can theoretically come from any website. It's
// very unlikely that a malicious site would care about hacking someone's
// unit tests, let alone be able to find the test server while it's
// running, but it's good practice to check the origin anyway.
final message = event as dom.MessageEvent;
if (message.origin == dom.window.location.origin &&
message.data == 'port') {
subscription.cancel();
var port = message.ports.first;
port.start();
var portSubscription =
dom.Subscription(port, 'message', allowInterop((dom.Event event) {
controller.local.sink.add((event as dom.MessageEvent).data);
}));

controller.local.stream.listen((data) {
port.postMessage({'data': data});
}, onDone: () {
port.postMessage({'event': 'done'});
portSubscription.cancel();
});
}
var channel = dom.createMessageChannel();
dom.window.parent
.postMessage('port', dom.window.location.origin, [channel.port2]);
var portSubscription = dom.Subscription(channel.port1, 'message',
allowInterop((dom.Event event) {
controller.local.sink.add((event as dom.MessageEvent).data);
}));
channel.port1.start();

// Send a ready message once we're listening so the host knows it's safe to
// start sending events.
// TODO: https://github.com/dart-lang/test/issues/2065 - remove href
dom.window.parent.postMessage(
jsify({'href': dom.window.location.href, 'ready': true}) as Object,
dom.window.location.origin);
controller.local.stream
.listen(channel.port1.postMessage, onDone: portSubscription.cancel);

return controller.foreign;
}
2 changes: 1 addition & 1 deletion pkgs/test/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: test
version: 1.24.6
version: 1.24.7-wip
description: >-
A full featured library for writing and running Dart tests across platforms.
repository: https://github.com/dart-lang/test/tree/master/pkgs/test
Expand Down

0 comments on commit 9b1828f

Please sign in to comment.