diff --git a/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart b/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart index 3cd67453b..9ef1f4e1f 100644 --- a/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart +++ b/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart @@ -112,13 +112,14 @@ class Dart2JsSupport extends CompilerSupport with JsHtmlWrapper { var jsPath = p.join(dir, '${p.basename(dartPath)}.browser_test.dart.js'); var bootstrapContent = ''' ${suiteConfig.metadata.languageVersionComment ?? await rootPackageLanguageVersionComment} + import 'dart:js_interop'; import 'package:test/src/bootstrap/browser.dart'; import 'package:test/src/runner/browser/dom.dart' as dom; import '${await absoluteUri(dartPath)}' as test; void main() { - dom.window.console.log(r'Startup for test path $dartPath'); + dom.window.console.log(r'Startup for test path $dartPath'.toJS); internalBootstrapBrowserTest(() => test.main); } '''; diff --git a/pkgs/test/lib/src/runner/browser/dom.dart b/pkgs/test/lib/src/runner/browser/dom.dart index a3a2d96bb..fe6a658a4 100644 --- a/pkgs/test/lib/src/runner/browser/dom.dart +++ b/pkgs/test/lib/src/runner/browser/dom.dart @@ -2,64 +2,51 @@ // 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. -// ignore: deprecated_member_use -import 'dart:js_util' as js_util; +import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; -// ignore: deprecated_member_use -import 'package:js/js.dart'; - -@JS() -@staticInterop -class Window extends EventTarget {} - -extension WindowExtension on Window { +extension type Window(EventTarget _) implements EventTarget { @pragma('dart2js:as:trust') - Window get parent => js_util.getProperty<dynamic>(this, 'parent') as Window; + Window get parent => getProperty('parent'.toJS) as Window; + external Location get location; - Console get console => js_util.getProperty(this, 'console') as Console; + + Console get console => getProperty('console'.toJS) as Console; + CSSStyleDeclaration? getComputedStyle(Element elt, [String? pseudoElt]) => - js_util.callMethod(this, 'getComputedStyle', <Object>[ + callMethodVarArgs('getComputedStyle'.toJS, <JSAny?>[ elt, - if (pseudoElt != null) pseudoElt + if (pseudoElt != null) pseudoElt.toJS ]) as CSSStyleDeclaration?; + external Navigator get navigator; + void postMessage(Object message, String targetOrigin, [List<MessagePort>? messagePorts]) => - js_util.callMethod(this, 'postMessage', <Object?>[ - js_util.jsify(message), - targetOrigin, - if (messagePorts != null) js_util.jsify(messagePorts) + callMethodVarArgs('postMessage'.toJS, <JSAny?>[ + message.jsify(), + targetOrigin.toJS, + if (messagePorts != null) messagePorts.toJS ]); } @JS('window') external Window get window; -@JS() -@staticInterop -class Console {} - -extension ConsoleExtension on Console { - external void log(Object? object); - external void warn(Object? object); +extension type Console(JSObject _) implements JSObject { + external void log(JSAny? object); + external void warn(JSAny? object); } -@JS() -@staticInterop -class Document extends Node {} - -extension DocumentExtension on Document { +extension type Document(Node _) implements Node { external Element? querySelector(String selectors); - Element createElement(String name, [Object? options]) => js_util.callMethod( - this, 'createElement', <Object>[name, if (options != null) options]) - as Element; -} -@JS() -@staticInterop -class HTMLDocument extends Document {} + Element createElement(String name, [Object? options]) => callMethodVarArgs( + 'createElement'.toJS, + <JSAny?>[name.toJS, if (options != null) options.jsify()]) as Element; +} -extension HTMLDocumentExtension on HTMLDocument { +extension type HTMLDocument(Document _) implements Document { external HTMLBodyElement? get body; external String? get title; } @@ -67,35 +54,19 @@ extension HTMLDocumentExtension on HTMLDocument { @JS('document') external HTMLDocument get document; -@JS() -@staticInterop -class Navigator {} - -extension NavigatorExtension on Navigator { +extension type Navigator(JSObject _) implements JSObject { external String get userAgent; } -@JS() -@staticInterop -class Element extends Node {} - -extension DomElementExtension on Element { +extension type Element(Node _) implements Node { external DomTokenList get classList; } -@JS() -@staticInterop -class HTMLElement extends Element {} - -@JS() -@staticInterop -class HTMLBodyElement extends HTMLElement {} +extension type HTMLElement(Element _) implements Element {} -@JS() -@staticInterop -class Node extends EventTarget {} +extension type HTMLBodyElement(HTMLElement _) implements HTMLElement {} -extension NodeExtension on Node { +extension type Node(EventTarget _) implements EventTarget { external Node appendChild(Node node); void remove() { if (parentNode != null) { @@ -108,47 +79,43 @@ extension NodeExtension on Node { external Node? get parentNode; } -@JS() -@staticInterop -class EventTarget {} - -extension EventTargetExtension on EventTarget { +extension type EventTarget(JSObject _) implements JSObject { void addEventListener(String type, EventListener? listener, [bool? useCapture]) { if (listener != null) { - js_util.callMethod<void>(this, 'addEventListener', - <Object>[type, listener, if (useCapture != null) useCapture]); + callMethodVarArgs('addEventListener'.toJS, <JSAny?>[ + type.toJS, + listener.toJS, + if (useCapture != null) useCapture.toJS + ]); } } void removeEventListener(String type, EventListener? listener, [bool? useCapture]) { if (listener != null) { - js_util.callMethod<void>(this, 'removeEventListener', - <Object>[type, listener, if (useCapture != null) useCapture]); + callMethodVarArgs('removeEventListener'.toJS, <JSAny?>[ + type.toJS, + listener.toJS, + if (useCapture != null) useCapture.toJS + ]); } } } typedef EventListener = void Function(Event event); -@JS() -@staticInterop -class Event {} - -extension EventExtension on Event { +extension type Event(JSObject _) implements JSObject { external void stopPropagation(); } -@JS() -@staticInterop -class MessageEvent extends Event {} +extension type MessageEvent(Event _) implements Event { + dynamic get data => getProperty('data'.toJS).dartify(); -extension MessageEventExtension on MessageEvent { - dynamic get data => js_util.dartify(js_util.getProperty(this, 'data')); external String get origin; + List<MessagePort> get ports => - js_util.getProperty<List>(this, 'ports').cast<MessagePort>(); + getProperty<JSArray>('ports'.toJS).toDart.cast<MessagePort>(); /// The source may be a `WindowProxy`, a `MessagePort`, or a `ServiceWorker`. /// @@ -156,77 +123,47 @@ extension MessageEventExtension on MessageEvent { /// the source will be a `WindowProxy` which has the same methods as [Window]. @pragma('dart2js:as:trust') MessageEventSource get source => - js_util.getProperty<dynamic>(this, 'source') as MessageEventSource; + getProperty('source'.toJS) as MessageEventSource; } -@JS() -@staticInterop -class MessageEventSource {} - -extension MessageEventSourceExtension on MessageEventSource { +extension type MessageEventSource(JSObject _) implements JSObject { @pragma('dart2js:as:trust') MessageEventSourceLocation? get location => - js_util.getProperty<dynamic>(this, 'location') - as MessageEventSourceLocation; + getProperty('location'.toJS) as MessageEventSourceLocation; } -@JS() -@staticInterop -class MessageEventSourceLocation {} - -extension MessageEventSourceLocationExtension on MessageEventSourceLocation { +extension type MessageEventSourceLocation(JSObject _) implements JSObject { external String? get href; } -@JS() -@staticInterop -class Location {} - -extension LocationExtension on Location { +extension type Location(JSObject _) implements JSObject { external String get href; external String get origin; } -@JS() -@staticInterop -class MessagePort extends EventTarget {} +extension type MessagePort(EventTarget _) implements EventTarget { + void postMessage(Object? message) => callMethodVarArgs( + 'postMessage'.toJS, <JSAny?>[if (message != null) message.jsify()]); -extension MessagePortExtension on MessagePort { - void postMessage(Object? message) => js_util.callMethod(this, 'postMessage', - <Object>[if (message != null) js_util.jsify(message) as Object]); external void start(); } -@JS() -@staticInterop -class CSSStyleDeclaration {} +extension type CSSStyleDeclaration(JSObject _) implements JSObject {} -@JS() -@staticInterop -class HTMLScriptElement extends HTMLElement {} - -extension HTMLScriptElementExtension on HTMLScriptElement { +extension type HTMLScriptElement(HTMLElement _) implements HTMLElement { external set src(String value); } HTMLScriptElement createHTMLScriptElement() => document.createElement('script') as HTMLScriptElement; -@JS() -@staticInterop -class DomTokenList {} - -extension DomTokenListExtension on DomTokenList { +extension type DomTokenList(JSObject _) implements JSObject { external void add(String value); external void remove(String value); external bool contains(String token); } -@JS() -@staticInterop -class HTMLIFrameElement extends HTMLElement {} - -extension HTMLIFrameElementExtension on HTMLIFrameElement { +extension type HTMLIFrameElement(HTMLElement _) implements HTMLElement { external String? get src; external set src(String? value); external Window get contentWindow; @@ -235,38 +172,28 @@ extension HTMLIFrameElementExtension on HTMLIFrameElement { HTMLIFrameElement createHTMLIFrameElement() => document.createElement('iframe') as HTMLIFrameElement; -@JS() -@staticInterop -class WebSocket extends EventTarget {} - -extension WebSocketExtension on WebSocket { - external void send(Object? data); +extension type WebSocket(EventTarget _) implements EventTarget { + external void send(JSAny? data); } WebSocket createWebSocket(String url) => - _callConstructor('WebSocket', <Object>[url])! as WebSocket; + _callConstructor('WebSocket', <JSAny?>[url.toJS])! as WebSocket; -@JS() -@staticInterop -class MessageChannel {} - -extension MessageChannelExtension on MessageChannel { +extension type MessageChannel(JSObject _) implements JSObject { external MessagePort get port1; external MessagePort get port2; } MessageChannel createMessageChannel() => - _callConstructor('MessageChannel', <Object>[])! as MessageChannel; - -Object? _findConstructor(String constructorName) => - js_util.getProperty(window, constructorName); + _callConstructor('MessageChannel', <JSAny?>[])! as MessageChannel; -Object? _callConstructor(String constructorName, List<Object?> args) { - final constructor = _findConstructor(constructorName); +Object? _callConstructor(String constructorName, List<JSAny?> args) { + final constructor = window.getProperty(constructorName.toJS) as JSFunction?; if (constructor == null) { return null; } - return js_util.callConstructor(constructor, args); + + return constructor.callAsConstructorVarArgs(args); } class Subscription { diff --git a/pkgs/test/lib/src/runner/browser/post_message_channel.dart b/pkgs/test/lib/src/runner/browser/post_message_channel.dart index 29bb3e547..229a33cd5 100644 --- a/pkgs/test/lib/src/runner/browser/post_message_channel.dart +++ b/pkgs/test/lib/src/runner/browser/post_message_channel.dart @@ -2,8 +2,7 @@ // 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. -// ignore: deprecated_member_use -import 'dart:js_util'; +import 'dart:js_interop'; import 'package:stream_channel/stream_channel.dart'; @@ -14,15 +13,15 @@ import 'dom.dart' as dom; /// /// Sends a [MessagePort] to the host page for the channel. StreamChannel<Object?> postMessageChannel() { - dom.window.console.log('Suite starting, sending channel to host'); + dom.window.console.log('Suite starting, sending channel to host'.toJS); var controller = StreamChannelController<Object?>(sync: true); 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) { + var portSubscription = + dom.Subscription(channel.port1, 'message', (dom.Event event) { controller.local.sink.add((event as dom.MessageEvent).data); - })); + }); channel.port1.start(); controller.local.stream diff --git a/pkgs/test/test/runner/coverage_test.dart b/pkgs/test/test/runner/coverage_test.dart index b149345e4..a49124ba8 100644 --- a/pkgs/test/test/runner/coverage_test.dart +++ b/pkgs/test/test/runner/coverage_test.dart @@ -83,9 +83,8 @@ void main() { await d.file('js_with_unicode_test.dart', ''' import 'dart:async'; - - import 'package:js/js.dart'; - import 'package:js/js_util.dart'; + import 'dart:js_interop'; + import 'dart:js_interop_unsafe'; import 'package:test/src/runner/browser/dom.dart' as dom; import 'package:test/test.dart'; @@ -95,9 +94,9 @@ void main() { final scriptLoaded = controller.stream.first; final script = dom.createHTMLScriptElement()..src = src; script.addEventListener('load', - allowInterop((_) { + (_) { controller.add('loaded'); - })); + }); dom.document.body!.appendChild(script); await scriptLoaded.timeout(Duration(seconds: 1)); } @@ -105,8 +104,8 @@ void main() { void main() { test("test 1", () async { await loadScript('file_with_unicode.js'); - expect(getProperty(dom.window, 'foo'), isNotNull); - callMethod(dom.window, 'foo', []); + expect(dom.window.getProperty('foo'.toJS), isNotNull); + dom.window.callMethodVarArgs('foo'.toJS, []); expect(true, isTrue); }); } diff --git a/pkgs/test/test/runner/test_on_test.dart b/pkgs/test/test/runner/test_on_test.dart index 96baf0ba4..f89d92f0a 100644 --- a/pkgs/test/test/runner/test_on_test.dart +++ b/pkgs/test/test/runner/test_on_test.dart @@ -201,7 +201,7 @@ Future<void> _writeTestFile(String filename, bool loadable = true}) { var buffer = StringBuffer(); if (suiteTestOn != null) buffer.writeln("@TestOn('$suiteTestOn')"); - if (!loadable) buffer.writeln("import 'dart:js_util';"); + if (!loadable) buffer.writeln("import 'dart:js_interop';"); buffer ..writeln("import 'package:test/test.dart';") diff --git a/pkgs/test/tool/host.dart b/pkgs/test/tool/host.dart index fd5a9418d..fe8c61448 100644 --- a/pkgs/test/tool/host.dart +++ b/pkgs/test/tool/host.dart @@ -7,9 +7,8 @@ library; import 'dart:async'; import 'dart:convert'; +import 'dart:js_interop'; -// ignore: deprecated_member_use -import 'package:js/js.dart'; import 'package:stack_trace/stack_trace.dart'; import 'package:stream_channel/stream_channel.dart'; import 'package:test/src/runner/browser/dom.dart' as dom; @@ -104,7 +103,7 @@ final _currentUrl = Uri.parse(dom.window.location.href); /// does mean that the server needs to be sure to nest its [MultiChannel]s at /// the same place the client does. void main() { - dom.window.console.log('Dart test runner browser host running'); + dom.window.console.log('Dart test runner browser host running'.toJS); if (_currentUrl.queryParameters['debug'] == 'true') { dom.document.body!.classList.add('debug'); } @@ -132,7 +131,7 @@ void main() { _domSubscriptions.remove(id)?.cancel(); default: dom.window.console - .warn('Unhandled message from test runner: $message'); + .warn('Unhandled message from test runner: $message'.toJS); } }); @@ -142,21 +141,21 @@ void main() { (_) => serverChannel.sink.add({'command': 'ping'})); var play = dom.document.querySelector('#play'); - play!.addEventListener('click', allowInterop((_) { + play!.addEventListener('click', (_) { if (!dom.document.body!.classList.contains('paused')) return; dom.document.body!.classList.remove('paused'); serverChannel.sink.add({'command': 'resume'}); - })); + }); - _jsApi = _JSApi(resume: allowInterop(() { + _jsApi = _JSApi(resume: () { if (!dom.document.body!.classList.contains('paused')) return; dom.document.body!.classList.remove('paused'); serverChannel.sink.add({'command': 'resume'}); - }), restartCurrent: allowInterop(() { + }, restartCurrent: () { serverChannel.sink.add({'command': 'restart'}); - })); + }); }, (error, stackTrace) { - dom.window.console.warn('$error\n${Trace.from(stackTrace).terse}'); + dom.window.console.warn('$error\n${Trace.from(stackTrace).terse}'.toJS); }); } @@ -169,13 +168,13 @@ MultiChannel<dynamic> _connectToServer() { dom.createWebSocket(_currentUrl.queryParameters['managerUrl']!); var controller = StreamChannelController<Object?>(sync: true); - webSocket.addEventListener('message', allowInterop((message) { + webSocket.addEventListener('message', (message) { controller.local.sink .add(jsonDecode((message as dom.MessageEvent).data as String)); - })); + }); controller.local.stream - .listen((message) => webSocket.send(jsonEncode(message))); + .listen((message) => webSocket.send(jsonEncode(message).toJS)); return MultiChannel(controller.foreign); } @@ -199,14 +198,14 @@ MultiChannel<dynamic> _connectToServer() { /// message channel port is active. StreamChannel<dynamic> _connectToIframe(String url, int id) { var suiteUrl = Uri.parse(url).removeFragment(); - dom.window.console.log('Starting suite $suiteUrl'); + dom.window.console.log('Starting suite $suiteUrl'.toJS); var iframe = dom.createHTMLIFrameElement(); _iframes[id] = iframe; var controller = StreamChannelController<Object?>(sync: true); late dom.Subscription windowSubscription; windowSubscription = - dom.Subscription(dom.window, 'message', allowInterop((dom.Event event) { + dom.Subscription(dom.window, 'message', (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 @@ -222,14 +221,13 @@ StreamChannel<dynamic> _connectToIframe(String url, int id) { switch (message.data) { case 'port': - dom.window.console.log('Connecting channel for suite $suiteUrl'); + dom.window.console.log('Connecting channel for suite $suiteUrl'.toJS); // The frame is starting and sending a port to forward for the suite. final port = message.ports.first; assert(!_domSubscriptions.containsKey(id)); - _domSubscriptions[id] = - dom.Subscription(port, 'message', allowInterop((event) { + _domSubscriptions[id] = dom.Subscription(port, 'message', (event) { controller.local.sink.add((event as dom.MessageEvent).data); - })); + }); port.start(); assert(!_subscriptions.containsKey(id)); @@ -239,11 +237,11 @@ StreamChannel<dynamic> _connectToIframe(String url, int id) { // loading the test. controller.local.sink.add(data); } - })); + }); iframe.src = url; dom.document.body!.appendChild(iframe); - dom.window.console.log('Appended iframe with src $url'); + dom.window.console.log('Appended iframe with src $url'.toJS); return controller.foreign; }