Skip to content

Commit

Permalink
refactor(ngdart): use new js interop for Testability
Browse files Browse the repository at this point in the history
Signed-off-by: Gavin Zhao <[email protected]>
  • Loading branch information
GZGavinZhao committed Jun 17, 2024
1 parent 0c02147 commit c408c63
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 29 deletions.
16 changes: 6 additions & 10 deletions ngdart/lib/src/testability/js_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import 'package:web/web.dart';
/// A JavaScript interface for interacting with AngularDart's `Testability` API.
///
/// This interfaces with a running AngularDart application.
@JS()
@anonymous
abstract class JsTestability {
extension type JsTestability._(JSObject _) implements JSObject {
external factory JsTestability({
required JSFunction isStable,
required JSFunction whenStable,
Expand All @@ -22,31 +20,29 @@ abstract class JsTestability {
/// framework. By default, this is determined by no known asynchronous tasks
/// (microtasks, or timers) being present but not yet executed within the
/// framework context.
bool isStable();
external bool isStable();

/// Invokes the provided [callback] when the application [isStable].
///
/// If the application was already stable at the time of this function being
/// invoked, [callback] is invoked with a value of `false` for `didWork`,
/// indicating that no asynchronous work was awaited before execution.
/// Otherwise a value of `true` is passed.
void whenStable(JSFunction callback);
external void whenStable(JSFunction callback);
}

/// A JavaScript interface for interacting with AngularDart's `TestabilityRegistry` API.
///
/// A global registry of `Testability` instances given an app root element.
@JS()
@anonymous
abstract class JsTestabilityRegistry {
extension type JsTestabilityRegistry._(JSObject _) implements JSObject {
external factory JsTestabilityRegistry({
required JSFunction getAngularTestability,
required JSFunction getAllAngularTestabilities,
});

/// Returns the registered testability instance for [appRoot], or `null`.
JsTestability? getAngularTestability(Element appRoot);
external JsTestability? getAngularTestability(Element appRoot);

/// Returns all testability instances registered.
List<JsTestability> getAllAngularTestabilities();
external JSArray<JsTestability> getAllAngularTestabilities();
}
43 changes: 24 additions & 19 deletions ngdart/lib/src/testability/js_impl.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
part of 'testability.dart';

@JS('ngTestabilityRegistries')
external List<JsTestabilityRegistry>? _ngJsTestabilityRegistries;
external JSArray<JsTestabilityRegistry>? _ngJsTestabilityRegistries;

@JS('getAngularTestability')
external set _jsGetAngularTestability(JSFunction function);
Expand All @@ -10,7 +10,7 @@ external set _jsGetAngularTestability(JSFunction function);
external set _jsGetAllAngularTestabilities(JSFunction function);

@JS('frameworkStabilizers')
external List<Object?>? _jsFrameworkStabilizers;
external JSArray<JSFunction>? _jsFrameworkStabilizers;

class _JSTestabilityProxy implements _TestabilityProxy {
const _JSTestabilityProxy();
Expand All @@ -19,23 +19,25 @@ class _JSTestabilityProxy implements _TestabilityProxy {
void addToWindow(TestabilityRegistry registry) {
var registries = _ngJsTestabilityRegistries;
if (registries == null) {
registries = <JsTestabilityRegistry>[];
registries = JSArray();
_ngJsTestabilityRegistries = registries;
_jsGetAngularTestability = _getAngularTestability.toJS;
_jsGetAllAngularTestabilities = _getAllAngularTestabilities.toJS;
(_jsFrameworkStabilizers ??= <Object?>[]).add(_whenAllStable.toJS);
((_jsFrameworkStabilizers ??= JSArray()) as List<JSFunction>).add(
((JSFunction callback) => _whenAllStable(callback as void Function()))
.toJS);
}
registries.add(registry.asJsApi());
}

/// For every registered [TestabilityRegistry], tries `getAngularTestability`.
static JsTestability? _getAngularTestability(Element element) {
final registry = _ngJsTestabilityRegistries;
if (registry == null) {
final registries = _ngJsTestabilityRegistries;
if (registries == null) {
return null;
}
for (var i = 0; i < registry.length; i++) {
final result = registry[i].getAngularTestability(element);
for (final registry in (registries as List<JsTestabilityRegistry>)) {
final result = registry.getAngularTestability(element);
if (result != null) {
return result;
}
Expand All @@ -44,22 +46,23 @@ class _JSTestabilityProxy implements _TestabilityProxy {
}

/// For every registered [TestabilityRegistry], returns the JS API for it.
static List<JsTestability> _getAllAngularTestabilities() {
final registry = _ngJsTestabilityRegistries;
if (registry == null) {
return <JsTestability>[];
static JSArray<JsTestability> _getAllAngularTestabilities() {
final registries = _ngJsTestabilityRegistries;
if (registries == null) {
return JSArray();
}
final result = <JsTestability>[];
for (var i = 0; i < registry.length; i++) {
final testabilities = registry[i].getAllAngularTestabilities();
for (final registry in (registries as List<JsTestabilityRegistry>)) {
final testabilities =
registry.getAllAngularTestabilities() as List<JsTestability>;
result.addAll(testabilities);
}
return result;
return result.toJS;
}

/// For every testability, calls [callback] when they _all_ report stable.
static void _whenAllStable(void Function() callback) {
final testabilities = _getAllAngularTestabilities();
final testabilities = _getAllAngularTestabilities() as List<JsTestability>;

var pendingStable = testabilities.length;

Expand All @@ -80,7 +83,8 @@ extension on Testability {
JsTestability asJsApi() {
return JsTestability(
isStable: (() => isStable).toJS,
whenStable: whenStable.toJS,
whenStable: ((JSFunction callback) =>
whenStable(callback as void Function())).toJS,
);
}
}
Expand All @@ -92,10 +96,11 @@ extension on TestabilityRegistry {
return dartTestability?.asJsApi();
}

List<JsTestability> getAllAngularTestabilities() {
JSArray<JsTestability> getAllAngularTestabilities() {
return allTestabilities
.map((testability) => testability.asJsApi())
.toList();
.toList()
.toJS;
}

return JsTestabilityRegistry(
Expand Down
4 changes: 4 additions & 0 deletions ngdart/lib/src/testability/testability.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const testabilityProvider = [
/// must be injected too.
// TODO(b/168535057): Add `dispose` function (to unsubscribe, remove elements).
@sealed
// @JS()
// @staticInterop
class Testability {
final NgZone _ngZone;

Expand All @@ -46,6 +48,7 @@ class Testability {
/// This is commonly referred to as _stable_, that-is that the DOM
/// representation of the app is synchronized with the Dart data and template
/// models, and no more changes are (currently) epected.
// @JSExport('whenStable')
void whenStable(void Function() callback) {
_storeCallback(callback);
_runCallbacksIfStable();
Expand All @@ -69,6 +72,7 @@ class Testability {
/// Whether the framework is no longer anticipating change detection.
///
/// See [whenStable] for details.
// @JSExport('isStable')
bool get isStable => !_ngZone.isRunning && !_ngZone.hasPendingMacrotasks;

void _runCallbacksIfStable() {
Expand Down

0 comments on commit c408c63

Please sign in to comment.