diff --git a/lib/web_ui/lib/src/engine/navigation/js_url_strategy.dart b/lib/web_ui/lib/src/engine/navigation/js_url_strategy.dart index 560b73f09121e..9014e517e25ab 100644 --- a/lib/web_ui/lib/src/engine/navigation/js_url_strategy.dart +++ b/lib/web_ui/lib/src/engine/navigation/js_url_strategy.dart @@ -29,6 +29,7 @@ typedef _HistoryMove = Future Function(int count); /// bridge from the app to the engine. @JS() @anonymous +@staticInterop abstract class JsUrlStrategy { /// Creates an instance of [JsUrlStrategy] from a bag of URL strategy /// functions. @@ -41,7 +42,9 @@ abstract class JsUrlStrategy { required _StateOperation replaceState, required _HistoryMove go, }); +} +extension JsUrlStrategyExtension on JsUrlStrategy { /// Adds a listener to the `popstate` event and returns a function that, when /// invoked, removes the listener. external ui.VoidCallback addPopStateListener(html.EventListener fn); diff --git a/lib/web_ui/lib/src/engine/navigation/url_strategy.dart b/lib/web_ui/lib/src/engine/navigation/url_strategy.dart index 3da031a022bcd..7d277c151e67c 100644 --- a/lib/web_ui/lib/src/engine/navigation/url_strategy.dart +++ b/lib/web_ui/lib/src/engine/navigation/url_strategy.dart @@ -5,6 +5,7 @@ import 'dart:async'; import 'dart:html' as html; +import 'package:js/js.dart' as js; import 'package:ui/ui.dart' as ui; import 'js_url_strategy.dart'; @@ -156,7 +157,7 @@ class CustomUrlStrategy extends UrlStrategy { @override ui.VoidCallback addPopStateListener(html.EventListener fn) => - delegate.addPopStateListener(fn); + delegate.addPopStateListener(js.allowInterop(fn)); @override String getPath() => delegate.getPath(); diff --git a/lib/web_ui/test/window_test.dart b/lib/web_ui/test/window_test.dart index f0ed95683b4e4..1aa5252288292 100644 --- a/lib/web_ui/test/window_test.dart +++ b/lib/web_ui/test/window_test.dart @@ -42,6 +42,29 @@ void testMain() { await window.resetHistory(); }); + test('window.defaultRouteName should work with JsUrlStrategy', () async { + dynamic state = {}; + final JsUrlStrategy jsUrlStrategy = JsUrlStrategy( + getPath: allowInterop(() => '/initial'), + getState: allowInterop(() => state), + addPopStateListener: allowInterop((html.EventListener listener) => () {}), + prepareExternalUrl: allowInterop((String value) => ''), + pushState: allowInterop((Object? newState, String title, String url) { + expect(newState is Map, true); + }), + replaceState: allowInterop((Object? newState, String title, String url) { + expect(newState is Map, true); + state = newState; + }), + go: allowInterop(([int? delta]) async { + expect(delta, -1); + })); + final CustomUrlStrategy strategy = + CustomUrlStrategy.fromJs(jsUrlStrategy); + await window.debugInitializeHistory(strategy, useSingle: true); + expect(window.defaultRouteName, '/initial'); + }); + test('window.defaultRouteName should not change', () async { final TestUrlStrategy strategy = TestUrlStrategy.fromEntry( const TestHistoryEntry('initial state', null, '/initial'),