blob: b6d62397054363d23aaa88cc19576d39a2c3fd5f [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:webview_flutter_android/src/android_webview.dart'
as android_webview;
import 'package:webview_flutter_android/src/android_webview_api_impls.dart';
import 'package:webview_flutter_android/src/instance_manager.dart';
import 'package:webview_flutter_android/webview_android_widget.dart';
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
import 'android_webview_test.mocks.dart' show MockTestWebViewHostApi;
import 'test_android_webview.pigeon.dart';
import 'webview_android_widget_test.mocks.dart';
@GenerateMocks(<Type>[
android_webview.FlutterAssetManager,
android_webview.WebSettings,
android_webview.WebStorage,
android_webview.WebView,
android_webview.WebResourceRequest,
WebViewAndroidDownloadListener,
WebViewAndroidJavaScriptChannel,
WebViewAndroidWebChromeClient,
WebViewAndroidWebViewClient,
JavascriptChannelRegistry,
WebViewPlatformCallbacksHandler,
WebViewProxy,
])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('WebViewAndroidWidget', () {
late MockFlutterAssetManager mockFlutterAssetManager;
late MockWebView mockWebView;
late MockWebSettings mockWebSettings;
late MockWebStorage mockWebStorage;
late MockWebViewProxy mockWebViewProxy;
late MockWebViewPlatformCallbacksHandler mockCallbacksHandler;
late WebViewAndroidWebViewClient webViewClient;
late WebViewAndroidDownloadListener downloadListener;
late WebViewAndroidWebChromeClient webChromeClient;
late MockJavascriptChannelRegistry mockJavascriptChannelRegistry;
late WebViewAndroidPlatformController testController;
setUp(() {
mockFlutterAssetManager = MockFlutterAssetManager();
mockWebView = MockWebView();
mockWebSettings = MockWebSettings();
mockWebStorage = MockWebStorage();
when(mockWebView.settings).thenReturn(mockWebSettings);
mockWebViewProxy = MockWebViewProxy();
when(mockWebViewProxy.createWebView(
useHybridComposition: anyNamed('useHybridComposition'),
)).thenReturn(mockWebView);
mockCallbacksHandler = MockWebViewPlatformCallbacksHandler();
mockJavascriptChannelRegistry = MockJavascriptChannelRegistry();
});
// Builds a AndroidWebViewWidget with default parameters.
Future<void> buildWidget(
WidgetTester tester, {
CreationParams? creationParams,
bool hasNavigationDelegate = false,
bool hasProgressTracking = false,
bool useHybridComposition = false,
}) async {
await tester.pumpWidget(WebViewAndroidWidget(
useHybridComposition: useHybridComposition,
creationParams: creationParams ??
CreationParams(
webSettings: WebSettings(
userAgent: const WebSetting<String?>.absent(),
hasNavigationDelegate: hasNavigationDelegate,
hasProgressTracking: hasProgressTracking,
)),
callbacksHandler: mockCallbacksHandler,
javascriptChannelRegistry: mockJavascriptChannelRegistry,
webViewProxy: mockWebViewProxy,
flutterAssetManager: mockFlutterAssetManager,
webStorage: mockWebStorage,
onBuildWidget: (WebViewAndroidPlatformController controller) {
testController = controller;
return Container();
},
));
webViewClient = testController.webViewClient;
downloadListener = testController.downloadListener;
webChromeClient = testController.webChromeClient;
}
testWidgets('WebViewAndroidWidget', (WidgetTester tester) async {
await buildWidget(tester);
verify(mockWebSettings.setDomStorageEnabled(true));
verify(mockWebSettings.setJavaScriptCanOpenWindowsAutomatically(true));
verify(mockWebSettings.setSupportMultipleWindows(true));
verify(mockWebSettings.setLoadWithOverviewMode(true));
verify(mockWebSettings.setUseWideViewPort(true));
verify(mockWebSettings.setDisplayZoomControls(false));
verify(mockWebSettings.setBuiltInZoomControls(true));
verifyInOrder(<Future<void>>[
mockWebView.setWebViewClient(webViewClient),
mockWebView.setDownloadListener(downloadListener),
mockWebView.setWebChromeClient(webChromeClient),
]);
});
testWidgets(
'Create Widget with Hybrid Composition',
(WidgetTester tester) async {
await buildWidget(tester, useHybridComposition: true);
verify(mockWebViewProxy.createWebView(useHybridComposition: true));
},
);
group('CreationParams', () {
testWidgets('initialUrl', (WidgetTester tester) async {
await buildWidget(
tester,
creationParams: CreationParams(
initialUrl: 'https://www.google.com',
webSettings: WebSettings(
userAgent: const WebSetting<String?>.absent(),
hasNavigationDelegate: false,
),
),
);
verify(mockWebView.loadUrl(
'https://www.google.com',
<String, String>{},
));
});
testWidgets('userAgent', (WidgetTester tester) async {
await buildWidget(
tester,
creationParams: CreationParams(
userAgent: 'MyUserAgent',
webSettings: WebSettings(
userAgent: const WebSetting<String?>.absent(),
hasNavigationDelegate: false,
),
),
);
verify(mockWebSettings.setUserAgentString('MyUserAgent'));
});
testWidgets('autoMediaPlaybackPolicy true', (WidgetTester tester) async {
await buildWidget(
tester,
creationParams: CreationParams(
webSettings: WebSettings(
userAgent: const WebSetting<String?>.absent(),
hasNavigationDelegate: false,
),
),
);
verify(mockWebSettings.setMediaPlaybackRequiresUserGesture(any));
});
testWidgets('autoMediaPlaybackPolicy false', (WidgetTester tester) async {
await buildWidget(
tester,
creationParams: CreationParams(
autoMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
webSettings: WebSettings(
userAgent: const WebSetting<String?>.absent(),
hasNavigationDelegate: false,
),
),
);
verify(mockWebSettings.setMediaPlaybackRequiresUserGesture(false));
});
testWidgets('javascriptChannelNames', (WidgetTester tester) async {
await buildWidget(
tester,
creationParams: CreationParams(
javascriptChannelNames: <String>{'a', 'b'},
webSettings: WebSettings(
userAgent: const WebSetting<String?>.absent(),
hasNavigationDelegate: false,
),
),
);
final List<dynamic> javaScriptChannels =
verify(mockWebView.addJavaScriptChannel(captureAny)).captured;
expect(javaScriptChannels[0].channelName, 'a');
expect(javaScriptChannels[1].channelName, 'b');
});
group('WebSettings', () {
testWidgets('javascriptMode', (WidgetTester tester) async {
await buildWidget(
tester,
creationParams: CreationParams(
webSettings: WebSettings(
userAgent: const WebSetting<String?>.absent(),
javascriptMode: JavascriptMode.unrestricted,
hasNavigationDelegate: false,
),
),
);
verify(mockWebSettings.setJavaScriptEnabled(true));
});
testWidgets('hasNavigationDelegate', (WidgetTester tester) async {
await buildWidget(
tester,
creationParams: CreationParams(
webSettings: WebSettings(
userAgent: const WebSetting<String?>.absent(),
hasNavigationDelegate: true,
),
),
);
expect(testController.webViewClient.handlesNavigation, isTrue);
expect(testController.webViewClient.shouldOverrideUrlLoading, isTrue);
});
testWidgets('debuggingEnabled true', (WidgetTester tester) async {
await buildWidget(
tester,
creationParams: CreationParams(
webSettings: WebSettings(
userAgent: const WebSetting<String?>.absent(),
debuggingEnabled: true,
hasNavigationDelegate: false,
),
),
);
verify(mockWebViewProxy.setWebContentsDebuggingEnabled(true));
});
testWidgets('debuggingEnabled false', (WidgetTester tester) async {
await buildWidget(
tester,
creationParams: CreationParams(
webSettings: WebSettings(
userAgent: const WebSetting<String?>.absent(),
debuggingEnabled: false,
hasNavigationDelegate: false,
),
),
);
verify(mockWebViewProxy.setWebContentsDebuggingEnabled(false));
});
testWidgets('userAgent', (WidgetTester tester) async {
await buildWidget(
tester,
creationParams: CreationParams(
webSettings: WebSettings(
userAgent: const WebSetting<String?>.of('myUserAgent'),
hasNavigationDelegate: false,
),
),
);
verify(mockWebSettings.setUserAgentString('myUserAgent'));
});
testWidgets('zoomEnabled', (WidgetTester tester) async {
await buildWidget(
tester,
creationParams: CreationParams(
webSettings: WebSettings(
userAgent: const WebSetting<String?>.absent(),
zoomEnabled: false,
hasNavigationDelegate: false,
),
),
);
verify(mockWebSettings.setSupportZoom(false));
});
});
});
group('WebViewPlatformController', () {
testWidgets('loadFile without "file://" prefix',
(WidgetTester tester) async {
await buildWidget(tester);
const String filePath = '/path/to/file.html';
await testController.loadFile(filePath);
verify(mockWebView.loadUrl(
'file://$filePath',
<String, String>{},
));
});
testWidgets('loadFile with "file://" prefix',
(WidgetTester tester) async {
await buildWidget(tester);
await testController.loadFile('file:///path/to/file.html');
verify(mockWebView.loadUrl(
'file:///path/to/file.html',
<String, String>{},
));
});
testWidgets('loadFile should setAllowFileAccess to true',
(WidgetTester tester) async {
await buildWidget(tester);
await testController.loadFile('file:///path/to/file.html');
verify(mockWebSettings.setAllowFileAccess(true));
});
testWidgets('loadFlutterAsset', (WidgetTester tester) async {
await buildWidget(tester);
const String assetKey = 'test_assets/index.html';
when(mockFlutterAssetManager.getAssetFilePathByName(assetKey))
.thenAnswer(
(_) => Future<String>.value('flutter_assets/$assetKey'));
when(mockFlutterAssetManager.list('flutter_assets/test_assets'))
.thenAnswer(
(_) => Future<List<String>>.value(<String>['index.html']));
await testController.loadFlutterAsset(assetKey);
verify(mockWebView.loadUrl(
'file:///android_asset/flutter_assets/$assetKey',
<String, String>{},
));
});
testWidgets('loadFlutterAsset with file in root',
(WidgetTester tester) async {
await buildWidget(tester);
const String assetKey = 'index.html';
when(mockFlutterAssetManager.getAssetFilePathByName(assetKey))
.thenAnswer(
(_) => Future<String>.value('flutter_assets/$assetKey'));
when(mockFlutterAssetManager.list('flutter_assets')).thenAnswer(
(_) => Future<List<String>>.value(<String>['index.html']));
await testController.loadFlutterAsset(assetKey);
verify(mockWebView.loadUrl(
'file:///android_asset/flutter_assets/$assetKey',
<String, String>{},
));
});
testWidgets(
'loadFlutterAsset throws ArgumentError when asset does not exists',
(WidgetTester tester) async {
await buildWidget(tester);
const String assetKey = 'test_assets/index.html';
when(mockFlutterAssetManager.getAssetFilePathByName(assetKey))
.thenAnswer(
(_) => Future<String>.value('flutter_assets/$assetKey'));
when(mockFlutterAssetManager.list('flutter_assets/test_assets'))
.thenAnswer((_) => Future<List<String>>.value(<String>['']));
expect(
() => testController.loadFlutterAsset(assetKey),
throwsA(
isA<ArgumentError>()
.having((ArgumentError error) => error.name, 'name', 'key')
.having((ArgumentError error) => error.message, 'message',
'Asset for key "$assetKey" not found.'),
),
);
});
testWidgets('loadHtmlString without base URL',
(WidgetTester tester) async {
await buildWidget(tester);
const String htmlString = '<html><body>Test data.</body></html>';
await testController.loadHtmlString(htmlString);
verify(mockWebView.loadDataWithBaseUrl(
data: htmlString,
mimeType: 'text/html',
));
});
testWidgets('loadHtmlString with base URL', (WidgetTester tester) async {
await buildWidget(tester);
const String htmlString = '<html><body>Test data.</body></html>';
await testController.loadHtmlString(
htmlString,
baseUrl: 'https://flutter.dev',
);
verify(mockWebView.loadDataWithBaseUrl(
baseUrl: 'https://flutter.dev',
data: htmlString,
mimeType: 'text/html',
));
});
testWidgets('loadUrl', (WidgetTester tester) async {
await buildWidget(tester);
await testController.loadUrl(
'https://www.google.com',
<String, String>{'a': 'header'},
);
verify(mockWebView.loadUrl(
'https://www.google.com',
<String, String>{'a': 'header'},
));
});
group('loadRequest', () {
testWidgets('Throws ArgumentError for empty scheme',
(WidgetTester tester) async {
await buildWidget(tester);
expect(
() async => testController.loadRequest(
WebViewRequest(
uri: Uri.parse('www.google.com'),
method: WebViewRequestMethod.get,
),
),
throwsA(const TypeMatcher<ArgumentError>()));
});
testWidgets('GET without headers', (WidgetTester tester) async {
await buildWidget(tester);
await testController.loadRequest(WebViewRequest(
uri: Uri.parse('https://www.google.com'),
method: WebViewRequestMethod.get,
));
verify(mockWebView.loadUrl(
'https://www.google.com',
<String, String>{},
));
});
testWidgets('GET with headers', (WidgetTester tester) async {
await buildWidget(tester);
await testController.loadRequest(WebViewRequest(
uri: Uri.parse('https://www.google.com'),
method: WebViewRequestMethod.get,
headers: <String, String>{'a': 'header'},
));
verify(mockWebView.loadUrl(
'https://www.google.com',
<String, String>{'a': 'header'},
));
});
testWidgets('POST without body', (WidgetTester tester) async {
await buildWidget(tester);
await testController.loadRequest(WebViewRequest(
uri: Uri.parse('https://www.google.com'),
method: WebViewRequestMethod.post,
));
verify(mockWebView.postUrl(
'https://www.google.com',
Uint8List(0),
));
});
testWidgets('POST with body', (WidgetTester tester) async {
await buildWidget(tester);
final Uint8List body = Uint8List.fromList('Test Body'.codeUnits);
await testController.loadRequest(WebViewRequest(
uri: Uri.parse('https://www.google.com'),
method: WebViewRequestMethod.post,
body: body));
verify(mockWebView.postUrl(
'https://www.google.com',
body,
));
});
});
testWidgets('no update to userAgentString when there is no change',
(WidgetTester tester) async {
await buildWidget(tester);
reset(mockWebSettings);
await testController.updateSettings(WebSettings(
userAgent: const WebSetting<String>.absent(),
));
verifyNever(mockWebSettings.setUserAgentString(any));
});
testWidgets('update null userAgentString with empty string',
(WidgetTester tester) async {
await buildWidget(tester);
reset(mockWebSettings);
await testController.updateSettings(WebSettings(
userAgent: const WebSetting<String?>.of(null),
));
verify(mockWebSettings.setUserAgentString(''));
});
testWidgets('currentUrl', (WidgetTester tester) async {
await buildWidget(tester);
when(mockWebView.getUrl())
.thenAnswer((_) => Future<String>.value('https://www.google.com'));
expect(
testController.currentUrl(), completion('https://www.google.com'));
});
testWidgets('canGoBack', (WidgetTester tester) async {
await buildWidget(tester);
when(mockWebView.canGoBack()).thenAnswer(
(_) => Future<bool>.value(false),
);
expect(testController.canGoBack(), completion(false));
});
testWidgets('canGoForward', (WidgetTester tester) async {
await buildWidget(tester);
when(mockWebView.canGoForward()).thenAnswer(
(_) => Future<bool>.value(true),
);
expect(testController.canGoForward(), completion(true));
});
testWidgets('goBack', (WidgetTester tester) async {
await buildWidget(tester);
await testController.goBack();
verify(mockWebView.goBack());
});
testWidgets('goForward', (WidgetTester tester) async {
await buildWidget(tester);
await testController.goForward();
verify(mockWebView.goForward());
});
testWidgets('reload', (WidgetTester tester) async {
await buildWidget(tester);
await testController.reload();
verify(mockWebView.reload());
});
testWidgets('clearCache', (WidgetTester tester) async {
await buildWidget(tester);
await testController.clearCache();
verify(mockWebView.clearCache(true));
verify(mockWebStorage.deleteAllData());
});
testWidgets('evaluateJavascript', (WidgetTester tester) async {
await buildWidget(tester);
when(mockWebView.evaluateJavascript('runJavaScript')).thenAnswer(
(_) => Future<String>.value('returnString'),
);
expect(
testController.evaluateJavascript('runJavaScript'),
completion('returnString'),
);
});
testWidgets('runJavascriptReturningResult', (WidgetTester tester) async {
await buildWidget(tester);
when(mockWebView.evaluateJavascript('runJavaScript')).thenAnswer(
(_) => Future<String>.value('returnString'),
);
expect(
testController.runJavascriptReturningResult('runJavaScript'),
completion('returnString'),
);
});
testWidgets('runJavascript', (WidgetTester tester) async {
await buildWidget(tester);
when(mockWebView.evaluateJavascript('runJavaScript')).thenAnswer(
(_) => Future<String>.value('returnString'),
);
expect(
testController.runJavascript('runJavaScript'),
completes,
);
});
testWidgets('addJavascriptChannels', (WidgetTester tester) async {
await buildWidget(tester);
await testController.addJavascriptChannels(<String>{'c', 'd'});
final List<dynamic> javaScriptChannels =
verify(mockWebView.addJavaScriptChannel(captureAny)).captured;
expect(javaScriptChannels[0].channelName, 'c');
expect(javaScriptChannels[1].channelName, 'd');
});
testWidgets('removeJavascriptChannels', (WidgetTester tester) async {
await buildWidget(tester);
await testController.addJavascriptChannels(<String>{'c', 'd'});
await testController.removeJavascriptChannels(<String>{'c', 'd'});
final List<dynamic> javaScriptChannels =
verify(mockWebView.removeJavaScriptChannel(captureAny)).captured;
expect(javaScriptChannels[0].channelName, 'c');
expect(javaScriptChannels[1].channelName, 'd');
});
testWidgets('getTitle', (WidgetTester tester) async {
await buildWidget(tester);
when(mockWebView.getTitle())
.thenAnswer((_) => Future<String>.value('Web Title'));
expect(testController.getTitle(), completion('Web Title'));
});
testWidgets('scrollTo', (WidgetTester tester) async {
await buildWidget(tester);
await testController.scrollTo(1, 2);
verify(mockWebView.scrollTo(1, 2));
});
testWidgets('scrollBy', (WidgetTester tester) async {
await buildWidget(tester);
await testController.scrollBy(3, 4);
verify(mockWebView.scrollBy(3, 4));
});
testWidgets('getScrollX', (WidgetTester tester) async {
await buildWidget(tester);
when(mockWebView.getScrollX()).thenAnswer((_) => Future<int>.value(23));
expect(testController.getScrollX(), completion(23));
});
testWidgets('getScrollY', (WidgetTester tester) async {
await buildWidget(tester);
when(mockWebView.getScrollY()).thenAnswer((_) => Future<int>.value(25));
expect(testController.getScrollY(), completion(25));
});
});
group('WebViewPlatformCallbacksHandler', () {
testWidgets('onPageStarted', (WidgetTester tester) async {
await buildWidget(tester);
webViewClient.onPageStarted(mockWebView, 'https://google.com');
verify(mockCallbacksHandler.onPageStarted('https://google.com'));
});
testWidgets('onPageFinished', (WidgetTester tester) async {
await buildWidget(tester);
webViewClient.onPageFinished(mockWebView, 'https://google.com');
verify(mockCallbacksHandler.onPageFinished('https://google.com'));
});
testWidgets('onWebResourceError from onReceivedError',
(WidgetTester tester) async {
await buildWidget(tester);
webViewClient.onReceivedError(
mockWebView,
android_webview.WebViewClient.errorAuthentication,
'description',
'https://google.com',
);
final WebResourceError error =
verify(mockCallbacksHandler.onWebResourceError(captureAny))
.captured
.single as WebResourceError;
expect(error.description, 'description');
expect(error.errorCode, -4);
expect(error.failingUrl, 'https://google.com');
expect(error.domain, isNull);
expect(error.errorType, WebResourceErrorType.authentication);
});
testWidgets('onWebResourceError from onReceivedRequestError',
(WidgetTester tester) async {
await buildWidget(tester);
webViewClient.onReceivedRequestError(
mockWebView,
android_webview.WebResourceRequest(
url: 'https://google.com',
isForMainFrame: true,
isRedirect: false,
hasGesture: false,
method: 'POST',
requestHeaders: <String, String>{},
),
android_webview.WebResourceError(
errorCode: android_webview.WebViewClient.errorUnsafeResource,
description: 'description',
),
);
final WebResourceError error =
verify(mockCallbacksHandler.onWebResourceError(captureAny))
.captured
.single as WebResourceError;
expect(error.description, 'description');
expect(error.errorCode, -16);
expect(error.failingUrl, 'https://google.com');
expect(error.domain, isNull);
expect(error.errorType, WebResourceErrorType.unsafeResource);
});
testWidgets('onNavigationRequest from urlLoading',
(WidgetTester tester) async {
await buildWidget(tester, hasNavigationDelegate: true);
when(mockCallbacksHandler.onNavigationRequest(
isForMainFrame: argThat(isTrue, named: 'isForMainFrame'),
url: 'https://google.com',
)).thenReturn(true);
webViewClient.urlLoading(mockWebView, 'https://google.com');
verify(mockCallbacksHandler.onNavigationRequest(
url: 'https://google.com',
isForMainFrame: true,
));
verify(mockWebView.loadUrl('https://google.com', <String, String>{}));
});
testWidgets('onNavigationRequest from requestLoading',
(WidgetTester tester) async {
await buildWidget(tester, hasNavigationDelegate: true);
when(mockCallbacksHandler.onNavigationRequest(
isForMainFrame: argThat(isTrue, named: 'isForMainFrame'),
url: 'https://google.com',
)).thenReturn(true);
webViewClient.requestLoading(
mockWebView,
android_webview.WebResourceRequest(
url: 'https://google.com',
isForMainFrame: true,
isRedirect: false,
hasGesture: false,
method: 'POST',
requestHeaders: <String, String>{},
),
);
verify(mockCallbacksHandler.onNavigationRequest(
url: 'https://google.com',
isForMainFrame: true,
));
verify(mockWebView.loadUrl('https://google.com', <String, String>{}));
});
group('JavascriptChannelRegistry', () {
testWidgets('onJavascriptChannelMessage', (WidgetTester tester) async {
await buildWidget(tester);
await testController.addJavascriptChannels(<String>{'hello'});
final WebViewAndroidJavaScriptChannel javaScriptChannel =
verify(mockWebView.addJavaScriptChannel(captureAny))
.captured
.single as WebViewAndroidJavaScriptChannel;
javaScriptChannel.postMessage('goodbye');
verify(mockJavascriptChannelRegistry.onJavascriptChannelMessage(
'hello',
'goodbye',
));
});
});
});
});
group('WebViewProxy', () {
late MockTestWebViewHostApi mockPlatformHostApi;
late InstanceManager instanceManager;
setUp(() {
// WebViewProxy calls static methods that can't be mocked, so the mocks
// have to be set up at the next layer down, by mocking the implementation
// of WebView itstelf.
mockPlatformHostApi = MockTestWebViewHostApi();
TestWebViewHostApi.setup(mockPlatformHostApi);
instanceManager = InstanceManager(onWeakReferenceRemoved: (_) {});
android_webview.WebView.api =
WebViewHostApiImpl(instanceManager: instanceManager);
});
test('setWebContentsDebuggingEnabled true', () {
const WebViewProxy webViewProxy = WebViewProxy();
webViewProxy.setWebContentsDebuggingEnabled(true);
verify(mockPlatformHostApi.setWebContentsDebuggingEnabled(true));
});
test('setWebContentsDebuggingEnabled false', () {
const WebViewProxy webViewProxy = WebViewProxy();
webViewProxy.setWebContentsDebuggingEnabled(false);
verify(mockPlatformHostApi.setWebContentsDebuggingEnabled(false));
});
});
group('WebViewAndroidWebViewClient', () {
test(
'urlLoading should call loadUrl when onNavigationRequestCallback returns true',
() {
final Completer<void> completer = Completer<void>();
final WebViewAndroidWebViewClient webViewClient =
WebViewAndroidWebViewClient.handlesNavigation(
onPageStartedCallback: (_) {},
onPageFinishedCallback: (_) {},
onWebResourceErrorCallback: (_) {},
onNavigationRequestCallback: ({
required bool isForMainFrame,
required String url,
}) =>
true,
loadUrl: (String url, Map<String, String>? headers) async {
completer.complete();
});
webViewClient.urlLoading(MockWebView(), 'https://flutter.dev');
expect(completer.isCompleted, isTrue);
});
test(
'urlLoading should call loadUrl when onNavigationRequestCallback returns a Future true',
() async {
final Completer<void> completer = Completer<void>();
final WebViewAndroidWebViewClient webViewClient =
WebViewAndroidWebViewClient.handlesNavigation(
onPageStartedCallback: (_) {},
onPageFinishedCallback: (_) {},
onWebResourceErrorCallback: (_) {},
onNavigationRequestCallback: ({
required bool isForMainFrame,
required String url,
}) =>
Future<bool>.value(true),
loadUrl: (String url, Map<String, String>? headers) async {
completer.complete();
});
webViewClient.urlLoading(MockWebView(), 'https://flutter.dev');
expect(completer.future, completes);
});
test(
'urlLoading should not call laodUrl when onNavigationRequestCallback returns false',
() async {
final WebViewAndroidWebViewClient webViewClient =
WebViewAndroidWebViewClient.handlesNavigation(
onPageStartedCallback: (_) {},
onPageFinishedCallback: (_) {},
onWebResourceErrorCallback: (_) {},
onNavigationRequestCallback: ({
required bool isForMainFrame,
required String url,
}) =>
false,
loadUrl: (String url, Map<String, String>? headers) async {
fail(
'loadUrl should not be called if onNavigationRequestCallback returns false.');
});
webViewClient.urlLoading(MockWebView(), 'https://flutter.dev');
});
test(
'urlLoading should not call loadUrl when onNavigationRequestCallback returns a Future false',
() {
final WebViewAndroidWebViewClient webViewClient =
WebViewAndroidWebViewClient.handlesNavigation(
onPageStartedCallback: (_) {},
onPageFinishedCallback: (_) {},
onWebResourceErrorCallback: (_) {},
onNavigationRequestCallback: ({
required bool isForMainFrame,
required String url,
}) =>
Future<bool>.value(false),
loadUrl: (String url, Map<String, String>? headers) async {
fail(
'loadUrl should not be called if onNavigationRequestCallback returns false.');
});
webViewClient.urlLoading(MockWebView(), 'https://flutter.dev');
});
test(
'requestLoading should call loadUrl when onNavigationRequestCallback returns true',
() {
final Completer<void> completer = Completer<void>();
final MockWebResourceRequest mockRequest = MockWebResourceRequest();
when(mockRequest.isForMainFrame).thenReturn(true);
when(mockRequest.url).thenReturn('https://flutter.dev');
final WebViewAndroidWebViewClient webViewClient =
WebViewAndroidWebViewClient.handlesNavigation(
onPageStartedCallback: (_) {},
onPageFinishedCallback: (_) {},
onWebResourceErrorCallback: (_) {},
onNavigationRequestCallback: ({
required bool isForMainFrame,
required String url,
}) =>
true,
loadUrl: (String url, Map<String, String>? headers) async {
expect(url, 'https://flutter.dev');
completer.complete();
});
webViewClient.requestLoading(MockWebView(), mockRequest);
expect(completer.isCompleted, isTrue);
});
test(
'requestLoading should call loadUrl when onNavigationRequestCallback returns a Future true',
() async {
final Completer<void> completer = Completer<void>();
final MockWebResourceRequest mockRequest = MockWebResourceRequest();
when(mockRequest.isForMainFrame).thenReturn(true);
when(mockRequest.url).thenReturn('https://flutter.dev');
final WebViewAndroidWebViewClient webViewClient =
WebViewAndroidWebViewClient.handlesNavigation(
onPageStartedCallback: (_) {},
onPageFinishedCallback: (_) {},
onWebResourceErrorCallback: (_) {},
onNavigationRequestCallback: ({
required bool isForMainFrame,
required String url,
}) =>
Future<bool>.value(true),
loadUrl: (String url, Map<String, String>? headers) async {
expect(url, 'https://flutter.dev');
completer.complete();
});
webViewClient.requestLoading(MockWebView(), mockRequest);
expect(completer.future, completes);
});
test(
'requestLoading should not call loadUrl when onNavigationRequestCallback returns false',
() {
final MockWebResourceRequest mockRequest = MockWebResourceRequest();
when(mockRequest.isForMainFrame).thenReturn(true);
when(mockRequest.url).thenReturn('https://flutter.dev');
final WebViewAndroidWebViewClient webViewClient =
WebViewAndroidWebViewClient.handlesNavigation(
onPageStartedCallback: (_) {},
onPageFinishedCallback: (_) {},
onWebResourceErrorCallback: (_) {},
onNavigationRequestCallback: ({
required bool isForMainFrame,
required String url,
}) =>
false,
loadUrl: (String url, Map<String, String>? headers) {
fail(
'loadUrl should not be called if onNavigationRequestCallback returns false.');
});
webViewClient.requestLoading(MockWebView(), mockRequest);
});
test(
'requestLoading should not call loadUrl when onNavigationRequestCallback returns a Future false',
() {
final MockWebResourceRequest mockRequest = MockWebResourceRequest();
when(mockRequest.isForMainFrame).thenReturn(true);
when(mockRequest.url).thenReturn('https://flutter.dev');
final WebViewAndroidWebViewClient webViewClient =
WebViewAndroidWebViewClient.handlesNavigation(
onPageStartedCallback: (_) {},
onPageFinishedCallback: (_) {},
onWebResourceErrorCallback: (_) {},
onNavigationRequestCallback: ({
required bool isForMainFrame,
required String url,
}) =>
Future<bool>.value(false),
loadUrl: (String url, Map<String, String>? headers) {
fail(
'loadUrl should not be called if onNavigationRequestCallback returns false.');
});
webViewClient.requestLoading(MockWebView(), mockRequest);
});
});
}