Skip to content

Commit 2739bbf

Browse files
authored
[web] Provide a hook to disable location strategy (flutter#18969)
1 parent 74291b7 commit 2739bbf

File tree

3 files changed

+63
-9
lines changed

3 files changed

+63
-9
lines changed

lib/web_ui/lib/src/engine/history.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ class BrowserHistory {
5353
}
5454
}
5555

56+
/// Returns the currently active location strategy.
57+
@visibleForTesting
58+
LocationStrategy get locationStrategy => _locationStrategy;
59+
5660
/// The path of the current location of the user's browser.
5761
String get currentPath => _locationStrategy?.path ?? '/';
5862

lib/web_ui/lib/src/engine/window.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ ui.VoidCallback scheduleFrameCallback;
1717
class EngineWindow extends ui.Window {
1818
EngineWindow() {
1919
_addBrightnessMediaQueryListener();
20+
js.context['_flutter_web_set_location_strategy'] = (LocationStrategy strategy) {
21+
locationStrategy = strategy;
22+
};
23+
registerHotRestartListener(() {
24+
js.context['_flutter_web_set_location_strategy'] = null;
25+
});
2026
}
2127

2228
@override
@@ -178,6 +184,10 @@ class EngineWindow extends ui.Window {
178184
_browserHistory.locationStrategy = strategy;
179185
}
180186

187+
/// Returns the currently active location strategy.
188+
@visibleForTesting
189+
LocationStrategy get locationStrategy => _browserHistory.locationStrategy;
190+
181191
@override
182192
ui.VoidCallback get onTextScaleFactorChanged => _onTextScaleFactorChanged;
183193
ui.VoidCallback _onTextScaleFactorChanged;

lib/web_ui/test/window_test.dart

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
// found in the LICENSE file.
44

55
// @dart = 2.6
6+
import 'dart:async';
7+
import 'dart:html' as html;
8+
import 'dart:js_util' as js_util;
69
import 'dart:typed_data';
710

811
import 'package:test/test.dart';
@@ -12,24 +15,18 @@ const MethodCodec codec = JSONMethodCodec();
1215

1316
void emptyCallback(ByteData date) {}
1417

15-
TestLocationStrategy _strategy;
16-
TestLocationStrategy get strategy => _strategy;
17-
set strategy(TestLocationStrategy newStrategy) {
18-
window.locationStrategy = _strategy = newStrategy;
19-
}
20-
2118
void main() {
2219
test('window.defaultRouteName should not change', () {
23-
strategy = TestLocationStrategy.fromEntry(TestHistoryEntry('initial state', null, '/initial'));
20+
window.locationStrategy = TestLocationStrategy.fromEntry(TestHistoryEntry('initial state', null, '/initial'));
2421
expect(window.defaultRouteName, '/initial');
2522

2623
// Changing the URL in the address bar later shouldn't affect [window.defaultRouteName].
27-
strategy.replaceState(null, null, '/newpath');
24+
window.locationStrategy.replaceState(null, null, '/newpath');
2825
expect(window.defaultRouteName, '/initial');
2926
});
3027

3128
test('window.defaultRouteName should reset after navigation platform message', () {
32-
strategy = TestLocationStrategy.fromEntry(TestHistoryEntry('initial state', null, '/initial'));
29+
window.locationStrategy = TestLocationStrategy.fromEntry(TestHistoryEntry('initial state', null, '/initial'));
3330
// Reading it multiple times should return the same value.
3431
expect(window.defaultRouteName, '/initial');
3532
expect(window.defaultRouteName, '/initial');
@@ -46,4 +43,47 @@ void main() {
4643
// reset to "/".
4744
expect(window.defaultRouteName, '/');
4845
});
46+
47+
test('can disable location strategy', () async {
48+
final testStrategy = TestLocationStrategy.fromEntry(
49+
TestHistoryEntry(null, null, '/'),
50+
);
51+
window.locationStrategy = testStrategy;
52+
53+
expect(window.locationStrategy, testStrategy);
54+
// A single listener should've been setup.
55+
expect(testStrategy.listeners, hasLength(1));
56+
// The initial entry should be there, plus another "flutter" entry.
57+
expect(testStrategy.history, hasLength(2));
58+
expect(testStrategy.history[0].state, <String, bool>{'origin': true});
59+
expect(testStrategy.history[1].state, <String, bool>{'flutter': true});
60+
expect(testStrategy.currentEntry, testStrategy.history[1]);
61+
62+
// Now, let's disable location strategy and make sure things get cleaned up.
63+
expect(() => jsSetLocationStrategy(null), returnsNormally);
64+
expect(window.locationStrategy, isNull);
65+
66+
// The listener is removed asynchronously.
67+
await Future<void>.delayed(const Duration(milliseconds: 10));
68+
69+
// No more listeners.
70+
expect(testStrategy.listeners, isEmpty);
71+
// History should've moved back to the initial entry.
72+
expect(testStrategy.history[0].state, <String, bool>{'origin': true});
73+
expect(testStrategy.currentEntry, testStrategy.history[0]);
74+
});
75+
76+
test('js interop throws on wrong type', () {
77+
expect(() => jsSetLocationStrategy(123), throwsA(anything));
78+
expect(() => jsSetLocationStrategy('foo'), throwsA(anything));
79+
expect(() => jsSetLocationStrategy(false), throwsA(anything));
80+
});
81+
}
82+
83+
void jsSetLocationStrategy(dynamic strategy) {
84+
js_util.callMethod(
85+
html.window,
86+
'_flutter_web_set_location_strategy',
87+
<dynamic>[strategy],
88+
);
4989
}

0 commit comments

Comments
 (0)