Skip to content

Commit

Permalink
update browser history switching (flutter#23471)
Browse files Browse the repository at this point in the history
  • Loading branch information
chunhtai authored Jan 20, 2021
1 parent 2b994d5 commit c97bdae
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 5 deletions.
30 changes: 25 additions & 5 deletions lib/web_ui/lib/src/engine/window.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow {
}

BrowserHistory? _browserHistory;

bool _usingRouter = false;
Future<void> _useSingleEntryBrowserHistory() async {
if (_browserHistory is SingleEntryBrowserHistory) {
return;
Expand All @@ -61,14 +61,23 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow {
_browserHistory = SingleEntryBrowserHistory(urlStrategy: strategy);
}

Future<void> _useMultiEntryBrowserHistory() async {
if (_browserHistory is MultiEntriesBrowserHistory) {
return;
}
final UrlStrategy? strategy = _browserHistory?.urlStrategy;
await _browserHistory?.tearDown();
_browserHistory = MultiEntriesBrowserHistory(urlStrategy: strategy);
}

@visibleForTesting
Future<void> debugInitializeHistory(
UrlStrategy? strategy, {
required bool useSingle,
}) async {
// Prevent any further customization of URL strategy.
_isUrlStrategySet = true;

_usingRouter = false;
await _browserHistory?.tearDown();
if (useSingle) {
_browserHistory = SingleEntryBrowserHistory(urlStrategy: strategy);
Expand All @@ -95,11 +104,22 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow {

switch (decoded.method) {
case 'routeUpdated':
await _useSingleEntryBrowserHistory();
browserHistory.setRouteName(arguments['routeName']);
if (!_usingRouter) {
await _useSingleEntryBrowserHistory();
browserHistory.setRouteName(arguments['routeName']);
} else {
assert(
false,
'Receives old navigator update in a router application. '
'This can happen if you use non-router versions of MaterialApp/'
'CupertinoApp/WidgetsApp together with the router versions of them.'
);
return false;
}
return true;
case 'routeInformationUpdated':
assert(browserHistory is MultiEntriesBrowserHistory);
await _useMultiEntryBrowserHistory();
_usingRouter = true;
browserHistory.setRouteName(
arguments['location'],
state: arguments['state'],
Expand Down
59 changes: 59 additions & 0 deletions lib/web_ui/test/window_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

// @dart = 2.6
import 'dart:async';
import 'dart:html' as html;
import 'dart:js_util' as js_util;
import 'dart:typed_data';
Expand Down Expand Up @@ -69,6 +70,64 @@ void testMain() {
expect(window.defaultRouteName, '/');
});

test('should throw when using nav1 and nav2 together',
() async {
await window.debugInitializeHistory(TestUrlStrategy.fromEntry(
TestHistoryEntry('initial state', null, '/initial'),
), useSingle: false);
// Receive nav1 update first.
Completer<void> callback = Completer<void>();
window.sendPlatformMessage(
'flutter/navigation',
JSONMethodCodec().encodeMethodCall(MethodCall(
'routeUpdated',
<String, dynamic>{'routeName': '/bar'},
)),
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory is SingleEntryBrowserHistory, true);
expect(window.browserHistory.urlStrategy.getPath(), '/bar');

// We can still receive nav2 update.
callback = Completer<void>();
window.sendPlatformMessage(
'flutter/navigation',
JSONMethodCodec().encodeMethodCall(MethodCall(
'routeInformationUpdated',
<String, dynamic>{
'location': '/baz',
'state': null,
},
)),
(_) { callback.complete(); },
);
await callback.future;
expect(window.browserHistory is MultiEntriesBrowserHistory, true);
expect(window.browserHistory.urlStrategy.getPath(), '/baz');

// Throws assertion error if it receives nav1 update after nav2 update.
AssertionError caughtAssertion;
await window.handleNavigationMessage(
JSONMethodCodec().encodeMethodCall(MethodCall(
'routeUpdated',
<String, dynamic>{'routeName': '/foo'},
))
).catchError((Object e) {
caughtAssertion = e as AssertionError;
});

expect(
caughtAssertion.message,
'Receives old navigator update in a router application. This can '
'happen if you use non-router versions of '
'MaterialApp/CupertinoApp/WidgetsApp together with the router versions of them.'
);
// The history does not change.
expect(window.browserHistory is MultiEntriesBrowserHistory, true);
expect(window.browserHistory.urlStrategy.getPath(), '/baz');
});

test('can disable location strategy', () async {
// Disable URL strategy.
expect(() => jsSetUrlStrategy(null), returnsNormally);
Expand Down

0 comments on commit c97bdae

Please sign in to comment.