Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
62 changes: 53 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,51 @@ 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 in a microtask.
final Completer<void> microtaskCompleter = Completer<void>.sync();
scheduleMicrotask(() {
microtaskCompleter.complete();
});
await microtaskCompleter.future;

// 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],
);
}