Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[web] Provide a hook to disable location strategy #18969

Merged
merged 2 commits into from
Jun 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/web_ui/lib/src/engine/history.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ class BrowserHistory {
}
}

/// Returns the currently active location strategy.
@visibleForTesting
LocationStrategy get locationStrategy => _locationStrategy;

/// The path of the current location of the user's browser.
String get currentPath => _locationStrategy?.path ?? '/';

Expand Down
10 changes: 10 additions & 0 deletions lib/web_ui/lib/src/engine/window.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ ui.VoidCallback scheduleFrameCallback;
class EngineWindow extends ui.Window {
EngineWindow() {
_addBrightnessMediaQueryListener();
js.context['_flutter_web_set_location_strategy'] = (LocationStrategy strategy) {
locationStrategy = strategy;
};
registerHotRestartListener(() {
js.context['_flutter_web_set_location_strategy'] = null;
});
}

@override
Expand Down Expand Up @@ -178,6 +184,10 @@ class EngineWindow extends ui.Window {
_browserHistory.locationStrategy = strategy;
}

/// Returns the currently active location strategy.
@visibleForTesting
LocationStrategy get locationStrategy => _browserHistory.locationStrategy;

@override
ui.VoidCallback get onTextScaleFactorChanged => _onTextScaleFactorChanged;
ui.VoidCallback _onTextScaleFactorChanged;
Expand Down
58 changes: 49 additions & 9 deletions lib/web_ui/test/window_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// 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';

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

void emptyCallback(ByteData date) {}

TestLocationStrategy _strategy;
TestLocationStrategy get strategy => _strategy;
set strategy(TestLocationStrategy newStrategy) {
window.locationStrategy = _strategy = newStrategy;
}

void main() {
test('window.defaultRouteName should not change', () {
strategy = TestLocationStrategy.fromEntry(TestHistoryEntry('initial state', null, '/initial'));
window.locationStrategy = TestLocationStrategy.fromEntry(TestHistoryEntry('initial state', null, '/initial'));
expect(window.defaultRouteName, '/initial');

// Changing the URL in the address bar later shouldn't affect [window.defaultRouteName].
strategy.replaceState(null, null, '/newpath');
window.locationStrategy.replaceState(null, null, '/newpath');
expect(window.defaultRouteName, '/initial');
});

test('window.defaultRouteName should reset after navigation platform message', () {
strategy = TestLocationStrategy.fromEntry(TestHistoryEntry('initial state', null, '/initial'));
window.locationStrategy = TestLocationStrategy.fromEntry(TestHistoryEntry('initial state', null, '/initial'));
// Reading it multiple times should return the same value.
expect(window.defaultRouteName, '/initial');
expect(window.defaultRouteName, '/initial');
Expand All @@ -46,4 +43,47 @@ void main() {
// reset to "/".
expect(window.defaultRouteName, '/');
});

test('can disable location strategy', () async {
final testStrategy = TestLocationStrategy.fromEntry(
TestHistoryEntry(null, null, '/'),
);
window.locationStrategy = testStrategy;

expect(window.locationStrategy, testStrategy);
// A single listener should've been setup.
expect(testStrategy.listeners, hasLength(1));
// The initial entry should be there, plus another "flutter" entry.
expect(testStrategy.history, hasLength(2));
expect(testStrategy.history[0].state, <String, bool>{'origin': true});
expect(testStrategy.history[1].state, <String, bool>{'flutter': true});
expect(testStrategy.currentEntry, testStrategy.history[1]);

// Now, let's disable location strategy and make sure things get cleaned up.
expect(() => jsSetLocationStrategy(null), returnsNormally);
expect(window.locationStrategy, isNull);

// The listener is removed asynchronously.
await Future<void>.delayed(const Duration(milliseconds: 10));

// No more listeners.
expect(testStrategy.listeners, isEmpty);
// History should've moved back to the initial entry.
expect(testStrategy.history[0].state, <String, bool>{'origin': true});
expect(testStrategy.currentEntry, testStrategy.history[0]);
});

test('js interop throws on wrong type', () {
expect(() => jsSetLocationStrategy(123), throwsA(anything));
expect(() => jsSetLocationStrategy('foo'), throwsA(anything));
expect(() => jsSetLocationStrategy(false), throwsA(anything));
});
}

void jsSetLocationStrategy(dynamic strategy) {
js_util.callMethod(
html.window,
'_flutter_web_set_location_strategy',
<dynamic>[strategy],
);
}