import 'dart:async'; import 'dart:collection'; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:path_provider/path_provider.dart'; import '.env.dart'; class Foo { String? bar; String? baz; Foo({this.bar, this.baz}); Map toJson() { return {'bar': this.bar, 'baz': this.baz}; } } class MyInAppBrowser extends InAppBrowser { final Completer browserCreated = Completer(); final Completer firstPageLoaded = Completer(); MyInAppBrowser( {int? windowId, UnmodifiableListView? initialUserScripts}) : super(windowId: windowId, initialUserScripts: initialUserScripts); @override Future onBrowserCreated() async { browserCreated.complete(); } @override void onLoadStop(Uri? url) { super.onLoadStop(url); if (!firstPageLoaded.isCompleted) { firstPageLoaded.complete(); } } } class MyChromeSafariBrowser extends ChromeSafariBrowser { final Completer browserCreated = Completer(); final Completer firstPageLoaded = Completer(); final Completer browserClosed = Completer(); @override void onOpened() { browserCreated.complete(); } @override void onCompletedInitialLoad() { firstPageLoaded.complete(); } @override void onClosed() { browserClosed.complete(); } } void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); if (Platform.isAndroid) { AndroidInAppWebViewController.setWebContentsDebuggingEnabled(false); } group('InAppWebView', () { testWidgets('initialUrlRequest', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; final String? currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, 'https://flutter.dev/'); }); testWidgets('set/get options', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions(javaScriptEnabled: false)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; InAppWebViewGroupOptions? options = await controller.getOptions(); expect(options, isNotNull); expect(options!.crossPlatform.javaScriptEnabled, false); await controller.setOptions( options: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions(javaScriptEnabled: true))); options = await controller.getOptions(); expect(options, isNotNull); expect(options!.crossPlatform.javaScriptEnabled, true); }); group('javascript code evaluation', () { testWidgets('evaluateJavascript', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; var result = await controller.evaluateJavascript(source: """ [1, true, ["bar", 5], {"foo": "baz"}]; """); expect(result, isNotNull); expect(result[0], 1); expect(result[1], true); expect(listEquals(result[2] as List?, ["bar", 5]), true); expect( mapEquals(result[3]?.cast(), {"foo": "baz"}), true); }); testWidgets('evaluateJavascript with content world', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.evaluateJavascript( source: "var foo = 49;", contentWorld: ContentWorld.world(name: "custom-world")); var result = await controller.evaluateJavascript(source: "foo"); expect(result, isNull); result = await controller.evaluateJavascript( source: "foo", contentWorld: ContentWorld.world(name: "custom-world")); expect(result, 49); }); testWidgets('callAsyncJavaScript', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; final String functionBody = """ var p = new Promise(function (resolve, reject) { window.setTimeout(function() { if (x >= 0) { resolve(x); } else { reject(y); } }, 1000); }); await p; return p; """; var result = await controller.callAsyncJavaScript( functionBody: functionBody, arguments: {'x': 49, 'y': 'error message'}); expect(result, isNotNull); expect(result!.error, isNull); expect(result.value, 49); result = await controller.callAsyncJavaScript( functionBody: functionBody, arguments: {'x': -49, 'y': 'error message'}); expect(result, isNotNull); expect(result!.value, isNull); expect(result.error, 'error message'); }); testWidgets('callAsyncJavaScript with content world', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.callAsyncJavaScript( functionBody: "window.foo = 49;", contentWorld: ContentWorld.world(name: "custom-world")); var result = await controller.callAsyncJavaScript( functionBody: "return window.foo;"); expect(result, isNotNull); expect(result!.error, isNull); expect(result.value, isNull); result = await controller.callAsyncJavaScript( functionBody: "return window.foo;", contentWorld: ContentWorld.world(name: "custom-world")); expect(result, isNotNull); expect(result!.error, isNull); expect(result.value, 49); }); }); testWidgets('loadUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; var url = await pageLoads.stream.first; expect(url, 'https://flutter.dev/'); await controller.loadUrl( urlRequest: URLRequest(url: Uri.parse('https://www.google.com/'))); url = await pageLoads.stream.first; expect(url, 'https://www.google.com/'); pageLoads.close(); }); testWidgets('loadUrl with headers', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageStarts = StreamController.broadcast(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions(javaScriptEnabled: true)), onLoadStart: (controller, url) { pageStarts.add(url!.toString()); }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; final Map headers = { 'test_header': 'flutter_test_header' }; await controller.loadUrl( urlRequest: URLRequest( url: Uri.parse('https://flutter-header-echo.herokuapp.com/'), headers: headers)); final String? currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, 'https://flutter-header-echo.herokuapp.com/'); await pageStarts.stream.firstWhere((String url) => url == currentUrl); await pageLoads.stream.firstWhere((String url) => url == currentUrl); final String content = await controller.evaluateJavascript( source: 'document.documentElement.innerText'); expect(content.contains('flutter_test_header'), isTrue); pageStarts.close(); pageLoads.close(); }); group("iOS loadFileURL", () { late Directory appSupportDir; late File fileHtml; late File fileJs; setUpAll(() async { appSupportDir = (await getApplicationSupportDirectory())!; final Directory htmlFolder = Directory('${appSupportDir.path}/html/'); if (!await htmlFolder.exists()) { await htmlFolder.create(recursive: true); } final Directory jsFolder = Directory('${appSupportDir.path}/js/'); if (!await jsFolder.exists()) { await jsFolder.create(recursive: true); } var html = """ file scheme """; fileHtml = File(htmlFolder.path + "index.html"); fileHtml.writeAsStringSync(html); var js = """ console.log('message'); """; fileJs = File(jsFolder.path + "main.js"); fileJs.writeAsStringSync(js); }); testWidgets('initialUrl with file:// scheme and allowingReadAccessTo', (WidgetTester tester) async { final Completer consoleMessageShouldNotComplete = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('file://${fileHtml.path}')), onConsoleMessage: (controller, consoleMessage) { consoleMessageShouldNotComplete.complete(consoleMessage); }, ), ), ); var result = await consoleMessageShouldNotComplete.future .timeout(const Duration(seconds: 2), onTimeout: () => null); expect(result, null); final Completer consoleMessageCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('file://${fileHtml.path}')), initialOptions: InAppWebViewGroupOptions( ios: IOSInAppWebViewOptions( allowingReadAccessTo: Uri.parse('file://${appSupportDir.path}/'))), onConsoleMessage: (controller, consoleMessage) { consoleMessageCompleter.complete(consoleMessage); }, ), ), ); final ConsoleMessage consoleMessage = await consoleMessageCompleter.future; expect(consoleMessage.messageLevel, ConsoleMessageLevel.LOG); expect(consoleMessage.message, 'message'); }, skip: !Platform.isIOS); testWidgets( 'loadUrl with file:// scheme and iosAllowingReadAccessTo argument', (WidgetTester tester) async { final Completer consoleMessageShouldNotComplete = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), onWebViewCreated: (controller) { controller.loadUrl( urlRequest: URLRequest(url: Uri.parse('file://${fileHtml.path}'))); }, onConsoleMessage: (controller, consoleMessage) { consoleMessageShouldNotComplete.complete(consoleMessage); }, ), ), ); var result = await consoleMessageShouldNotComplete.future .timeout(const Duration(seconds: 2), onTimeout: () => null); expect(result, null); final Completer consoleMessageCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), onWebViewCreated: (controller) { controller.loadUrl( urlRequest: URLRequest(url: Uri.parse('file://${fileHtml.path}')), iosAllowingReadAccessTo: Uri.parse('file://${appSupportDir.path}/')); }, onConsoleMessage: (controller, consoleMessage) { consoleMessageCompleter.complete(consoleMessage); }, ), ), ); final ConsoleMessage consoleMessage = await consoleMessageCompleter.future; expect(consoleMessage.messageLevel, ConsoleMessageLevel.LOG); expect(consoleMessage.message, 'message'); }, skip: !Platform.isIOS); }, skip: !Platform.isIOS); testWidgets('JavaScript Handler', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageStarted = Completer(); final Completer pageLoaded = Completer(); final Completer handlerFoo = Completer(); final Completer handlerFooWithArgs = Completer(); final List messagesReceived = []; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialFile: "test_assets/in_app_webview_javascript_handler_test.html", onWebViewCreated: (controller) { controllerCompleter.complete(controller); controller.addJavaScriptHandler( handlerName: 'handlerFoo', callback: (args) { handlerFoo.complete(); return Foo(bar: 'bar_value', baz: 'baz_value'); }); controller.addJavaScriptHandler( handlerName: 'handlerFooWithArgs', callback: (args) { messagesReceived.add(args[0] as int); messagesReceived.add(args[1] as bool); messagesReceived.add(args[2] as List?); messagesReceived.add(args[3]?.cast() as Map?); messagesReceived.add(args[4]?.cast() as Map?); handlerFooWithArgs.complete(); }); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions(javaScriptEnabled: true)), onLoadStart: (controller, url) { pageStarted.complete(); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); await pageStarted.future; await pageLoaded.future; await handlerFoo.future; await handlerFooWithArgs.future; expect(messagesReceived[0], 1); expect(messagesReceived[1], true); expect( listEquals(messagesReceived[2] as List?, ["bar", 5]), true); expect(mapEquals(messagesReceived[3], {"foo": "baz"}), true); expect( mapEquals( messagesReceived[4], {"bar": "bar_value", "baz": "baz_value"}), true); }); testWidgets('resize webview', (WidgetTester tester) async { final String resizeTest = ''' Resize test '''; final String resizeTestBase64 = base64Encode(const Utf8Encoder().convert(resizeTest)); final Completer resizeCompleter = Completer(); final Completer pageStarted = Completer(); final Completer pageLoaded = Completer(); final Completer controllerCompleter = Completer(); final GlobalKey key = GlobalKey(); final InAppWebView webView = InAppWebView( key: key, initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,$resizeTestBase64')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); controller.addJavaScriptHandler( handlerName: 'resize', callback: (args) { resizeCompleter.complete(true); }); }, onLoadStart: (controller, url) { pageStarted.complete(); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions(javaScriptEnabled: true)), ); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Column( children: [ SizedBox( width: 200, height: 200, child: webView, ), ], ), ), ); await controllerCompleter.future; await pageStarted.future; await pageLoaded.future; expect(resizeCompleter.isCompleted, false); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Column( children: [ SizedBox( width: 400, height: 400, child: webView, ), ], ), ), ); await resizeCompleter.future; }); testWidgets('set custom userAgent', (WidgetTester tester) async { final Completer controllerCompleter1 = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, userAgent: 'Custom_User_Agent1', )), onWebViewCreated: (controller) { controllerCompleter1.complete(controller); }, ), ), ); InAppWebViewController controller1 = await controllerCompleter1.future; final String customUserAgent1 = await controller1.evaluateJavascript(source: 'navigator.userAgent;'); expect(customUserAgent1, 'Custom_User_Agent1'); await controller1.setOptions( options: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( userAgent: 'Custom_User_Agent2', ))); final String customUserAgent2 = await controller1.evaluateJavascript(source: 'navigator.userAgent;'); expect(customUserAgent2, 'Custom_User_Agent2'); }); group('Video playback policy', () { String videoTestBase64 = ""; setUpAll(() async { final ByteData videoData = await rootBundle.load('test_assets/sample_video.mp4'); final String base64VideoData = base64Encode(Uint8List.view(videoData.buffer)); final String videoTest = ''' Video auto play '''; videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest)); }); testWidgets('Auto media playback', (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,$videoTestBase64')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, mediaPlaybackRequiresUserGesture: false)), onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; bool isPaused = await controller.evaluateJavascript(source: 'isPaused();'); expect(isPaused, false); controllerCompleter = Completer(); pageLoaded = Completer(); // We change the key to re-create a new webview as we change the mediaPlaybackRequiresUserGesture await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,$videoTestBase64')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, mediaPlaybackRequiresUserGesture: true)), onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); controller = await controllerCompleter.future; await pageLoaded.future; isPaused = await controller.evaluateJavascript(source: 'isPaused();'); expect(isPaused, true); }); testWidgets('Video plays inline when allowsInlineMediaPlayback is true', (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); Completer onEnterFullscreenCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,$videoTestBase64')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, mediaPlaybackRequiresUserGesture: false, ), ios: IOSInAppWebViewOptions(allowsInlineMediaPlayback: true)), onLoadStop: (controller, url) { pageLoaded.complete(); }, onEnterFullscreen: (controller) { onEnterFullscreenCompleter.complete(); }, ), ), ); await pageLoaded.future; expect(onEnterFullscreenCompleter.future, doesNotComplete); }); testWidgets( 'Video plays fullscreen when allowsInlineMediaPlayback is false', (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); Completer onEnterFullscreenCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,$videoTestBase64')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, mediaPlaybackRequiresUserGesture: false, ), ios: IOSInAppWebViewOptions(allowsInlineMediaPlayback: false)), onLoadStop: (controller, url) { pageLoaded.complete(); }, onEnterFullscreen: (controller) { onEnterFullscreenCompleter.complete(); }, ), ), ); await pageLoaded.future; await expectLater(onEnterFullscreenCompleter.future, completes); }, skip: true); testWidgets('exit fullscreen event', (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); Completer onExitFullscreenCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,$videoTestBase64')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, mediaPlaybackRequiresUserGesture: false, ), ios: IOSInAppWebViewOptions(allowsInlineMediaPlayback: false)), onLoadStop: (controller, url) { pageLoaded.complete(); }, onExitFullscreen: (controller) { onExitFullscreenCompleter.complete(); }, ), ), ); InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await Future.delayed(Duration(seconds: 2)); await controller.evaluateJavascript(source: "exitFullscreen();"); await expectLater(onExitFullscreenCompleter.future, completes); }, skip: true /*!Platform.isAndroid*/); }); group('Audio playback policy', () { String audioTestBase64 = ""; setUpAll(() async { final ByteData audioData = await rootBundle.load('test_assets/sample_audio.ogg'); final String base64AudioData = base64Encode(Uint8List.view(audioData.buffer)); final String audioTest = ''' Audio auto play '''; audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest)); }); testWidgets('Auto media playback', (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageStarted = Completer(); Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,$audioTestBase64')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, mediaPlaybackRequiresUserGesture: false)), onLoadStart: (controller, url) { pageStarted.complete(); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); InAppWebViewController controller = await controllerCompleter.future; await pageStarted.future; await pageLoaded.future; bool isPaused = await controller.evaluateJavascript(source: 'isPaused();'); expect(isPaused, false); controllerCompleter = Completer(); pageStarted = Completer(); pageLoaded = Completer(); // We change the key to re-create a new webview as we change the mediaPlaybackRequiresUserGesture await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,$audioTestBase64')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, mediaPlaybackRequiresUserGesture: true), ), onLoadStart: (controller, url) { pageStarted.complete(); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); controller = await controllerCompleter.future; await pageStarted.future; await pageLoaded.future; isPaused = await controller.evaluateJavascript(source: 'isPaused();'); expect(isPaused, true); }); }); testWidgets('getTitle', (WidgetTester tester) async { final String getTitleTest = ''' Some title '''; final String getTitleTestBase64 = base64Encode(const Utf8Encoder().convert(getTitleTest)); final Completer pageStarted = Completer(); final Completer pageLoaded = Completer(); final Completer controllerCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,$getTitleTestBase64')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStart: (controller, url) { pageStarted.complete(); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageStarted.future; await pageLoaded.future; final String? title = await controller.getTitle(); expect(title, 'Some title'); }); group('Programmatic Scroll', () { testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { final String scrollTestPage = '''
'''; final String scrollTestPageBase64 = base64Encode(const Utf8Encoder().convert(scrollTestPage)); final Completer pageLoaded = Completer(); final Completer controllerCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.scrollTo(x: 0, y: 0); await tester.pumpAndSettle(Duration(seconds: 3)); // Check scrollTo() const int X_SCROLL = 123; const int Y_SCROLL = 321; await controller.scrollTo(x: X_SCROLL, y: Y_SCROLL); await tester.pumpAndSettle(Duration(seconds: 2)); int? scrollPosX = await controller.getScrollX(); int? scrollPosY = await controller.getScrollY(); expect(scrollPosX, X_SCROLL); expect(scrollPosY, Y_SCROLL); // Check scrollBy() (on top of scrollTo()) await controller.scrollBy(x: X_SCROLL, y: Y_SCROLL); await tester.pumpAndSettle(Duration(seconds: 2)); scrollPosX = await controller.getScrollX(); scrollPosY = await controller.getScrollY(); expect(scrollPosX, X_SCROLL * 2); expect(scrollPosY, Y_SCROLL * 2); }); }); group('Android Hybrid Composition', () { testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { final String scrollTestPage = '''
'''; final String scrollTestPageBase64 = base64Encode(const Utf8Encoder().convert(scrollTestPage)); final Completer pageLoaded = Completer(); final Completer controllerCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( android: AndroidInAppWebViewOptions(useHybridComposition: true)), onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.scrollTo(x: 0, y: 0); await tester.pumpAndSettle(Duration(seconds: 3)); // Check scrollTo() const int X_SCROLL = 123; const int Y_SCROLL = 321; await controller.scrollTo(x: X_SCROLL, y: Y_SCROLL); await tester.pumpAndSettle(Duration(seconds: 2)); int? scrollPosX = await controller.getScrollX(); int? scrollPosY = await controller.getScrollY(); expect(scrollPosX, X_SCROLL); expect(scrollPosY, Y_SCROLL); // Check scrollBy() (on top of scrollTo()) await controller.scrollBy(x: X_SCROLL, y: Y_SCROLL); await tester.pumpAndSettle(Duration(seconds: 2)); scrollPosX = await controller.getScrollX(); scrollPosY = await controller.getScrollY(); expect(scrollPosX, X_SCROLL * 2); expect(scrollPosY, Y_SCROLL * 2); }, skip: !Platform.isAndroid); }, skip: !Platform.isAndroid); group('shouldOverrideUrlLoading', () { final String page = '''flutter_inappwebview'''; final String pageEncoded = 'data:text/html;charset=utf-8;base64,' + base64Encode(const Utf8Encoder().convert(page)); testWidgets('can allow requests', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse(pageEncoded)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, useShouldOverrideUrlLoading: true), ), shouldOverrideUrlLoading: (controller, navigationAction) async { return (navigationAction.request.url!.host .contains('youtube.com')) ? NavigationActionPolicy.CANCEL : NavigationActionPolicy.ALLOW; }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); await pageLoads.stream.first; // Wait for initial page load. final InAppWebViewController controller = await controllerCompleter.future; await controller.evaluateJavascript( source: 'location.href = "https://www.google.com/"'); await pageLoads.stream.first; // Wait for the next page load. final String? currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, 'https://www.google.com/'); pageLoads.close(); }); testWidgets( 'allow requests on iOS only if iosWKNavigationType == IOSWKNavigationType.LINK_ACTIVATED', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse(pageEncoded)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, useShouldOverrideUrlLoading: true), ), shouldOverrideUrlLoading: (controller, navigationAction) async { var isFirstLoad = navigationAction.request.url!.scheme == "data"; return (isFirstLoad || navigationAction.iosWKNavigationType == IOSWKNavigationType.LINK_ACTIVATED) ? NavigationActionPolicy.ALLOW : NavigationActionPolicy.CANCEL; }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); await pageLoads.stream.first; // Wait for initial page load. final InAppWebViewController controller = await controllerCompleter.future; await controller.evaluateJavascript( source: 'location.href = "https://www.google.com/"'); // There should never be any second page load, since our new URL is // blocked. Still wait for a potential page change for some time in order // to give the test a chance to fail. await pageLoads.stream .map((event) => event as String?) .first .timeout(const Duration(milliseconds: 500), onTimeout: () => null); String? currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, isNot('https://www.google.com/')); await controller.evaluateJavascript( source: 'document.querySelector("#link").click();'); await pageLoads.stream.first; // Wait for the next page load. currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, 'https://github.com/pichillilorenzo/flutter_inappwebview'); pageLoads.close(); }, skip: !Platform.isIOS); testWidgets('can block requests', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse(pageEncoded)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, useShouldOverrideUrlLoading: true), ), shouldOverrideUrlLoading: (controller, navigationAction) async { return (navigationAction.request.url!.host .contains('youtube.com')) ? NavigationActionPolicy.CANCEL : NavigationActionPolicy.ALLOW; }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); await pageLoads.stream.first; // Wait for initial page load. final InAppWebViewController controller = await controllerCompleter.future; await controller.evaluateJavascript( source: 'location.href = "https://www.youtube.com/"'); // There should never be any second page load, since our new URL is // blocked. Still wait for a potential page change for some time in order // to give the test a chance to fail. await pageLoads.stream .map((event) => event as String?) .first .timeout(const Duration(milliseconds: 500), onTimeout: () => null); final String? currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, isNot(contains('youtube.com'))); pageLoads.close(); }); testWidgets('supports asynchronous decisions', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse(pageEncoded)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, useShouldOverrideUrlLoading: true), ), shouldOverrideUrlLoading: (controller, navigationAction) async { var action = NavigationActionPolicy.CANCEL; action = await Future.delayed( const Duration(milliseconds: 10), () => NavigationActionPolicy.ALLOW); return action; }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); await pageLoads.stream.first; // Wait for initial page load. final InAppWebViewController controller = await controllerCompleter.future; await controller.evaluateJavascript( source: 'location.href = "https://www.google.com"'); await pageLoads.stream.first; // Wait for second page to load. final String? currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, 'https://www.google.com/'); pageLoads.close(); }); }); testWidgets('onLoadError', (WidgetTester tester) async { final Completer errorUrlCompleter = Completer(); final Completer errorCodeCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://www.notawebsite..com')), onLoadError: (controller, url, code, message) { errorUrlCompleter.complete(url.toString()); errorCodeCompleter.complete(code); }, ), ), ); final String url = await errorUrlCompleter.future; final int code = await errorCodeCompleter.future; if (Platform.isAndroid) { expect(code, -2); } else if (Platform.isIOS) { expect(code, -1003); } expect(url, 'https://www.notawebsite..com/'); }); testWidgets('onLoadError is not called with valid url', (WidgetTester tester) async { final Completer errorUrlCompleter = Completer(); final Completer errorCodeCompleter = Completer(); final Completer errorMessageCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+')), onLoadError: (controller, url, code, message) { errorUrlCompleter.complete(url.toString()); errorCodeCompleter.complete(code); errorMessageCompleter.complete(message); }, ), ), ); expect(errorUrlCompleter.future, doesNotComplete); expect(errorCodeCompleter.future, doesNotComplete); expect(errorMessageCompleter.future, doesNotComplete); }); testWidgets('launches with allowsBackForwardNavigationGestures true on iOS', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: SizedBox( width: 400, height: 300, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), initialOptions: InAppWebViewGroupOptions( ios: IOSInAppWebViewOptions( allowsBackForwardNavigationGestures: true)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, ), ), ), ); final InAppWebViewController controller = await controllerCompleter.future; final String? currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, contains('flutter.dev')); }); testWidgets('target _blank opens in same window', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, javaScriptCanOpenWindowsAutomatically: true), ), onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); await pageLoads.stream.first; final InAppWebViewController controller = await controllerCompleter.future; await controller.evaluateJavascript( source: 'window.open("about:blank", "_blank");'); await pageLoads.stream.first; final String? currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, 'about:blank'); pageLoads.close(); }); testWidgets( 'can open new window and go back', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, javaScriptCanOpenWindowsAutomatically: true), ), onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); await pageLoads.stream.first; final InAppWebViewController controller = await controllerCompleter.future; await controller.evaluateJavascript( source: 'window.open("https://github.com/flutter");'); await pageLoads.stream.first; expect((await controller.getUrl())?.toString(), contains('github.com/flutter')); await controller.goBack(); await pageLoads.stream.first; expect( (await controller.getUrl())?.toString(), contains('flutter.dev')); pageLoads.close(); }, skip: !Platform.isAndroid, ); testWidgets( 'javascript does not run in parent window', (WidgetTester tester) async { final String iframe = ''' '''; final String iframeTestBase64 = base64Encode(const Utf8Encoder().convert(iframe)); final String openWindowTest = ''' XSS test '''; final String openWindowTestBase64 = base64Encode(const Utf8Encoder().convert(openWindowTest)); final Completer controllerCompleter = Completer(); final Completer pageLoadCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse( 'data:text/html;charset=utf-8;base64,$openWindowTestBase64')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( javaScriptEnabled: true, javaScriptCanOpenWindowsAutomatically: true), ), onLoadStop: (controller, url) { pageLoadCompleter.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoadCompleter.future; expect(controller.evaluateJavascript(source: 'iframeLoaded'), completion(true)); expect( controller.evaluateJavascript( source: 'document.querySelector("p") && document.querySelector("p").textContent'), completion(null), ); }, skip: !Platform.isAndroid, ); testWidgets('intercept ajax request', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer shouldInterceptAjaxPostRequestCompleter = Completer(); final Completer> onAjaxReadyStateChangeCompleter = Completer>(); final Completer> onAjaxProgressCompleter = Completer>(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialData: InAppWebViewInitialData(data: """ InAppWebViewAjaxTest

InAppWebViewAjaxTest

"""), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, useShouldInterceptAjaxRequest: true, )), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, shouldInterceptAjaxRequest: (controller, ajaxRequest) async { if (ajaxRequest.url!.toString().endsWith("/test-ajax-post")) { ajaxRequest.responseType = 'json'; ajaxRequest.data = "firstname=Foo2&lastname=Bar2"; shouldInterceptAjaxPostRequestCompleter.complete(controller); } return ajaxRequest; }, onAjaxReadyStateChange: (controller, ajaxRequest) async { if (ajaxRequest.readyState == AjaxRequestReadyState.DONE && ajaxRequest.status == 200 && ajaxRequest.url!.toString().endsWith("/test-ajax-post")) { Map res = ajaxRequest.response; onAjaxReadyStateChangeCompleter.complete(res); } return AjaxRequestAction.PROCEED; }, onAjaxProgress: (controller, ajaxRequest) async { if (ajaxRequest.event!.type == AjaxRequestEventType.LOAD && ajaxRequest.url!.toString().endsWith("/test-ajax-post")) { Map res = ajaxRequest.response; onAjaxProgressCompleter.complete(res); } return AjaxRequestAction.PROCEED; }, ), ), ); await shouldInterceptAjaxPostRequestCompleter.future; final Map onAjaxReadyStateChangeValue = await onAjaxReadyStateChangeCompleter.future; final Map onAjaxProgressValue = await onAjaxProgressCompleter.future; expect( mapEquals(onAjaxReadyStateChangeValue, {'firstname': 'Foo2', 'lastname': 'Bar2'}), true); expect( mapEquals( onAjaxProgressValue, {'firstname': 'Foo2', 'lastname': 'Bar2'}), true); }); testWidgets('Content Blocker', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions(clearCache: true, contentBlockers: [ ContentBlocker( trigger: ContentBlockerTrigger(urlFilter: ".*", resourceType: [ ContentBlockerTriggerResourceType.IMAGE, ContentBlockerTriggerResourceType.STYLE_SHEET ], ifTopUrl: [ "https://flutter.dev/" ]), action: ContentBlockerAction( type: ContentBlockerActionType.BLOCK)) ])), onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); await expectLater(pageLoaded.future, completes); }); testWidgets('intercept fetch request', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer fetchGetCompleter = Completer(); final Completer> fetchPostCompleter = Completer>(); final Completer shouldInterceptFetchPostRequestCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialData: InAppWebViewInitialData(data: """ InAppWebViewFetchTest

InAppWebViewFetchTest

"""), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, useShouldInterceptFetchRequest: true, )), onWebViewCreated: (controller) { controllerCompleter.complete(controller); controller.addJavaScriptHandler( handlerName: "fetchGet", callback: (args) { fetchGetCompleter.complete(args[0].toString()); }); controller.addJavaScriptHandler( handlerName: "fetchPost", callback: (args) { fetchPostCompleter .complete(args[0] as Map); }); }, shouldInterceptFetchRequest: (controller, fetchRequest) async { if (fetchRequest.url!.toString().endsWith("/test-ajax-post")) { fetchRequest.body = utf8.encode("""{ "firstname": "Foo2", "lastname": "Bar2" } """) as Uint8List; shouldInterceptFetchPostRequestCompleter.complete(); } return fetchRequest; }, ), ), ); var fetchGetCompleterValue = await fetchGetCompleter.future; expect(fetchGetCompleterValue, '200'); await shouldInterceptFetchPostRequestCompleter.future; var fetchPostCompleterValue = await fetchPostCompleter.future; expect( mapEquals(fetchPostCompleterValue, {'firstname': 'Foo2', 'lastname': 'Bar2'}), true); }); testWidgets('Http Auth Credential Database', (WidgetTester tester) async { HttpAuthCredentialDatabase httpAuthCredentialDatabase = HttpAuthCredentialDatabase.instance(); final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); httpAuthCredentialDatabase.setHttpAuthCredential( protectionSpace: URLProtectionSpace( host: environment["NODE_SERVER_IP"]!, protocol: "http", realm: "Node", port: 8081), credential: URLCredential(username: "USERNAME", password: "PASSWORD")); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse("http://${environment["NODE_SERVER_IP"]}:8081/")), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, )), onLoadStop: (controller, url) { pageLoaded.complete(); }, onReceivedHttpAuthRequest: (controller, challenge) async { return new HttpAuthResponse( action: HttpAuthResponseAction.USE_SAVED_HTTP_AUTH_CREDENTIALS); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; final String h1Content = await controller.evaluateJavascript( source: "document.body.querySelector('h1').textContent"); expect(h1Content, "Authorized"); var credentials = await httpAuthCredentialDatabase.getHttpAuthCredentials( protectionSpace: URLProtectionSpace( host: environment["NODE_SERVER_IP"]!, protocol: "http", realm: "Node", port: 8081)); expect(credentials.length, 1); await httpAuthCredentialDatabase.clearAllAuthCredentials(); credentials = await httpAuthCredentialDatabase.getHttpAuthCredentials( protectionSpace: URLProtectionSpace( host: environment["NODE_SERVER_IP"]!, protocol: "http", realm: "Node", port: 8081)); expect(credentials, isEmpty); }); testWidgets('onReceivedHttpAuthRequest', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse("http://${environment["NODE_SERVER_IP"]}:8081/")), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, )), onLoadStop: (controller, url) { pageLoaded.complete(); }, onReceivedHttpAuthRequest: (controller, challenge) async { return new HttpAuthResponse( username: "USERNAME", password: "PASSWORD", action: HttpAuthResponseAction.PROCEED, permanentPersistence: true); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; final String h1Content = await controller.evaluateJavascript( source: "document.body.querySelector('h1').textContent"); expect(h1Content, "Authorized"); }); testWidgets('onConsoleMessage', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onConsoleMessageCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialFile: "test_assets/in_app_webview_on_console_message_test.html", onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onConsoleMessage: (controller, consoleMessage) { onConsoleMessageCompleter.complete(consoleMessage); }, ), ), ); final ConsoleMessage consoleMessage = await onConsoleMessageCompleter.future; expect(consoleMessage.message, 'message'); expect(consoleMessage.messageLevel, ConsoleMessageLevel.LOG); }); group("WebView Windows", () { testWidgets('onCreateWindow return false', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialFile: "test_assets/in_app_webview_on_create_window_test.html", initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, javaScriptCanOpenWindowsAutomatically: true, )), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { if (url!.toString() == "https://flutter.dev/") { pageLoaded.complete(); } }, onCreateWindow: (controller, createNavigationAction) async { controller.loadUrl(urlRequest: createNavigationAction.request); return false; }, ), ), ); await expectLater(pageLoaded.future, completes); }); testWidgets('onCreateWindow return true', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onCreateWindowCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialFile: "test_assets/in_app_webview_on_create_window_test.html", initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, javaScriptCanOpenWindowsAutomatically: true, ), android: AndroidInAppWebViewOptions(supportMultipleWindows: true)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onCreateWindow: (controller, createNavigationAction) async { onCreateWindowCompleter .complete(createNavigationAction.windowId); return true; }, ), ), ); var windowId = await onCreateWindowCompleter.future; final Completer windowControllerCompleter = Completer(); final Completer windowPageLoaded = Completer(); final Completer onCloseWindowCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), windowId: windowId, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, )), onWebViewCreated: (controller) { windowControllerCompleter.complete(controller); }, onLoadStop: (controller, url) async { if (url!.scheme != "about") { windowPageLoaded.complete(url.toString()); await controller.evaluateJavascript( source: "window.close();"); } }, onCloseWindow: (controller) { onCloseWindowCompleter.complete(); }, ), ), ); final String windowUrlLoaded = await windowPageLoaded.future; expect(windowUrlLoaded, "https://flutter.dev/"); await expectLater(onCloseWindowCompleter.future, completes); }); }); testWidgets('onDownloadStart', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onDownloadStartCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialData: InAppWebViewInitialData(data: """ InAppWebViewOnDownloadStartTest

InAppWebViewOnDownloadStartTest

download file """), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, useOnDownloadStart: true)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onDownloadStart: (controller, url) { onDownloadStartCompleter.complete(url.toString()); }, ), ), ); final String url = await onDownloadStartCompleter.future; expect(url, "http://${environment["NODE_SERVER_IP"]}:8082/test-download-file"); }); testWidgets('onFindResultReceived', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer numberOfMatchesCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialFile: "test_assets/in_app_webview_initial_file_test.html", initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, )), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { controller.findAllAsync(find: "InAppWebViewInitialFileTest"); }, onFindResultReceived: (controller, int activeMatchOrdinal, int numberOfMatches, bool isDoneCounting) async { if (isDoneCounting && !numberOfMatchesCompleter.isCompleted) { numberOfMatchesCompleter.complete(numberOfMatches); } }, ), ), ); final int numberOfMatches = await numberOfMatchesCompleter.future; expect(numberOfMatches, 2); }); testWidgets('javascript dialogs', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); final Completer alertCompleter = Completer(); final Completer confirmCompleter = Completer(); final Completer promptCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialFile: "test_assets/in_app_webview_on_js_dialog_test.html", initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, )), onWebViewCreated: (controller) { controllerCompleter.complete(controller); controller.addJavaScriptHandler( handlerName: 'confirm', callback: (args) { confirmCompleter.complete(args[0] as bool); }); controller.addJavaScriptHandler( handlerName: 'prompt', callback: (args) { promptCompleter.complete(args[0] as String); }); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, onJsAlert: (controller, jsAlertRequest) async { JsAlertResponseAction action = JsAlertResponseAction.CONFIRM; alertCompleter.complete(jsAlertRequest); return JsAlertResponse(handledByClient: true, action: action); }, onJsConfirm: (controller, jsConfirmRequest) async { JsConfirmResponseAction action = JsConfirmResponseAction.CONFIRM; return JsConfirmResponse(handledByClient: true, action: action); }, onJsPrompt: (controller, jsPromptRequest) async { JsPromptResponseAction action = JsPromptResponseAction.CONFIRM; return JsPromptResponse( handledByClient: true, action: action, value: 'new value'); }, ), ), ); await pageLoaded.future; final JsAlertRequest jsAlertRequest = await alertCompleter.future; expect(jsAlertRequest.message, 'alert message'); final bool onJsConfirmValue = await confirmCompleter.future; expect(onJsConfirmValue, true); final String onJsPromptValue = await promptCompleter.future; expect(onJsPromptValue, 'new value'); }); testWidgets('onLoadHttpError', (WidgetTester tester) async { final Completer errorUrlCompleter = Completer(); final Completer statusCodeCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://google.com/404')), onLoadHttpError: (controller, url, statusCode, description) async { errorUrlCompleter.complete(url.toString()); statusCodeCompleter.complete(statusCode); }, ), ), ); final String url = await errorUrlCompleter.future; final int code = await statusCodeCompleter.future; expect(url, 'https://google.com/404'); expect(code, 404); }); testWidgets('onLoadResourceCustomScheme', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer imageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialFile: "test_assets/in_app_webview_on_load_resource_custom_scheme_test.html", initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, resourceCustomSchemes: ["my-special-custom-scheme"])), onWebViewCreated: (controller) { controllerCompleter.complete(controller); controller.addJavaScriptHandler( handlerName: "imageLoaded", callback: (args) { imageLoaded.complete(); }); }, onLoadResourceCustomScheme: (controller, url) async { if (url.scheme == "my-special-custom-scheme") { var bytes = await rootBundle.load("test_assets/" + url .toString() .replaceFirst("my-special-custom-scheme://", "", 0)); var response = CustomSchemeResponse( data: bytes.buffer.asUint8List(), contentType: "image/svg+xml", contentEncoding: "utf-8"); return response; } return null; }, ), ), ); await expectLater(imageLoaded.future, completes); }); testWidgets('onLoadResource', (WidgetTester tester) async { List resourceList = [ "https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css", "https://code.jquery.com/jquery-3.3.1.min.js", "https://via.placeholder.com/100x50" ]; List resourceLoaded = []; final Completer loadedResourceCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialFile: "test_assets/in_app_webview_on_load_resource_test.html", initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, useOnLoadResource: true)), onLoadStop: (controller, url) { pageLoaded.complete(); }, onLoadResource: (controller, response) async { resourceLoaded.add(response.url!.toString()); if (resourceLoaded.length == resourceList.length) { loadedResourceCompleter.complete(); } }), ), ); await pageLoaded.future; await loadedResourceCompleter.future; expect(resourceLoaded, unorderedEquals(resourceList)); }); testWidgets('onUpdateVisitedHistory', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer firstPushCompleter = Completer(); final Completer secondPushCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse("https://flutter.dev/")), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions(clearCache: true)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, onUpdateVisitedHistory: (controller, url, androidIsReload) async { if (url!.toString().endsWith("second-push")) { secondPushCompleter.complete(); } else if (url.toString().endsWith("first-push")) { firstPushCompleter.complete(); } }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.evaluateJavascript(source: """ var state = {} var title = '' var url = 'first-push'; history.pushState(state, title, url); setTimeout(function() { var url = 'second-push'; history.pushState(state, title, url); }, 500); """); await firstPushCompleter.future; expect((await controller.getUrl())?.toString(), 'https://flutter.dev/first-push'); await secondPushCompleter.future; expect((await controller.getUrl())?.toString(), 'https://flutter.dev/second-push'); }); testWidgets('onProgressChanged', (WidgetTester tester) async { final Completer onProgressChangedCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, )), onProgressChanged: (controller, progress) { if (progress == 100) { onProgressChangedCompleter.complete(); } }, ), ), ); await expectLater(onProgressChangedCompleter.future, completes); }); testWidgets('androidOnSafeBrowsingHit', (WidgetTester tester) async { final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse('chrome://safe-browsing/match?type=malware')), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( // if I set javaScriptEnabled to true, it will crash! javaScriptEnabled: false, clearCache: true, ), android: AndroidInAppWebViewOptions( safeBrowsingEnabled: true, ), ), onWebViewCreated: (controller) { controller.android.startSafeBrowsing(); }, onLoadStop: (controller, url) { pageLoaded.complete(url!.toString()); }, androidOnSafeBrowsingHit: (controller, url, threatType) async { return SafeBrowsingResponse( report: true, action: SafeBrowsingResponseAction.PROCEED); }, ), ), ); final String url = await pageLoaded.future; expect(url, "chrome://safe-browsing/match?type=malware"); }, skip: !Platform.isAndroid); testWidgets('onScrollChanged', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); final Completer onScrollChangedCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, onScrollChanged: (controller, x, y) { if (x == 0 && y == 500) { onScrollChangedCompleter.complete(); } }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; controller.scrollTo(x: 0, y: 500); await tester.pumpAndSettle(Duration(seconds: 1)); await expectLater(onScrollChangedCompleter.future, completes); }); testWidgets('SSL request', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse( "https://${environment["NODE_SERVER_IP"]}:4433/")), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, onReceivedServerTrustAuthRequest: (controller, challenge) async { return new ServerTrustAuthResponse( action: ServerTrustAuthResponseAction.PROCEED); }, onReceivedClientCertRequest: (controller, challenge) async { return new ClientCertResponse( certificatePath: "test_assets/certificate.pfx", certificatePassword: "", androidKeyStoreType: "PKCS12", action: ClientCertResponseAction.PROCEED); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; final String h1Content = await controller.evaluateJavascript( source: "document.body.querySelector('h1').textContent"); expect(h1Content, "Authorized"); }); testWidgets('onPrint', (WidgetTester tester) async { final Completer onPrintCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onLoadStop: (controller, url) async { await controller.evaluateJavascript(source: "window.print();"); }, onPrint: (controller, url) { onPrintCompleter.complete(url?.toString()); }, ), ), ); final String url = await onPrintCompleter.future; expect(url, 'https://flutter.dev/'); }, skip: true); testWidgets('onWindowFocus', (WidgetTester tester) async { final Completer onWindowFocusCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onLoadStop: (controller, url) async { await controller.evaluateJavascript( source: 'window.dispatchEvent(new Event("focus"));'); }, onWindowFocus: (controller) { onWindowFocusCompleter.complete(); }, ), ), ); await expectLater(onWindowFocusCompleter.future, completes); }); testWidgets('onWindowBlur', (WidgetTester tester) async { final Completer onWindowBlurCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onLoadStop: (controller, url) async { await controller.evaluateJavascript( source: 'window.dispatchEvent(new Event("blur"));'); }, onWindowBlur: (controller) { onWindowBlurCompleter.complete(); }, ), ), ); await expectLater(onWindowBlurCompleter.future, completes); }); testWidgets('onPageCommitVisible', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onPageCommitVisibleCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onPageCommitVisible: (controller, url) { onPageCommitVisibleCompleter.complete(url?.toString()); }, ), ), ); final String? url = await onPageCommitVisibleCompleter.future; expect(url, 'https://flutter.dev/'); }); testWidgets('onTitleChanged', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); final Completer onTitleChangedCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, onTitleChanged: (controller, title) { if (title == "title test") { onTitleChangedCompleter.complete(); } }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.evaluateJavascript( source: "document.title = 'title test';"); await expectLater(onTitleChangedCompleter.future, completes); }); testWidgets('androidOnPermissionRequest', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); final Completer> onPermissionRequestCompleter = Completer>(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://permission.site/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, androidOnPermissionRequest: (controller, origin, resources) async { onPermissionRequestCompleter.complete(resources); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.evaluateJavascript( source: "document.querySelector('#camera').click();"); final List resources = await onPermissionRequestCompleter.future; expect(listEquals(resources, ['android.webkit.resource.VIDEO_CAPTURE']), true); }, skip: !Platform.isAndroid); testWidgets('androidShouldInterceptRequest', (WidgetTester tester) async { List resourceList = [ "https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css", "https://code.jquery.com/jquery-3.3.1.min.js", "https://via.placeholder.com/100x50" ]; List resourceLoaded = []; final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); final Completer loadedResourceCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialData: InAppWebViewInitialData(data: """ placeholder 100x50 """), initialOptions: InAppWebViewGroupOptions( android: AndroidInAppWebViewOptions( useShouldInterceptRequest: true)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, androidShouldInterceptRequest: (controller, request) async { resourceLoaded.add(request.url.toString()); if (resourceLoaded.length == resourceList.length) { loadedResourceCompleter.complete(); } return null; }, ), ), ); await pageLoaded.future; await loadedResourceCompleter.future; expect(resourceLoaded, containsAll(resourceList)); }, skip: !Platform.isAndroid); testWidgets('androidOnScaleChanged', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); final Completer onScaleChangedCompleter = Completer(); var listenForScaleChange = false; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, androidOnScaleChanged: (controller, oldScale, newScale) { if (listenForScaleChange) { onScaleChangedCompleter.complete(); } }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; listenForScaleChange = true; await controller.evaluateJavascript(source: """ var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width, initial-scale=2.0, maximum-scale=2.0, minimum-scale=2.0, user-scalable=no'); document.getElementsByTagName('head')[0].appendChild(meta); """); await expectLater(onScaleChangedCompleter.future, completes); }, skip: !Platform.isAndroid); testWidgets('androidOnReceivedIcon', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); final Completer onReceivedIconCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, androidOnReceivedIcon: (controller, icon) { onReceivedIconCompleter.complete(icon); }, ), ), ); await pageLoaded.future; final Uint8List icon = await onReceivedIconCompleter.future; expect(icon, isNotNull); }, skip: !Platform.isAndroid); testWidgets('androidOnReceivedTouchIconUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onReceivedTouchIconUrlCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialData: InAppWebViewInitialData(data: """ """), initialOptions: InAppWebViewGroupOptions( android: AndroidInAppWebViewOptions( useShouldInterceptRequest: true)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, androidOnReceivedTouchIconUrl: (controller, url, precomposed) { onReceivedTouchIconUrlCompleter.complete(url.toString()); }, ), ), ); final String url = await onReceivedTouchIconUrlCompleter.future; expect(url, "https://placehold.it/72x72"); }, skip: !Platform.isAndroid); testWidgets('androidOnJsBeforeUnload', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); final Completer onJsBeforeUnloadCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) async { await controller.evaluateJavascript(source: """ window.addEventListener('beforeunload', function (e) { e.preventDefault(); e.returnValue = ''; }); """); if (!pageLoaded.isCompleted) { pageLoaded.complete(); } }, androidOnJsBeforeUnload: (controller, jsBeforeUnloadRequest) async { onJsBeforeUnloadCompleter .complete(jsBeforeUnloadRequest.url.toString()); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.evaluateJavascript( source: "window.location.href = 'https://github.com/flutter';"); final String url = await onJsBeforeUnloadCompleter.future; expect(url, 'https://github.com/flutter'); }, skip: true /*!Platform.isAndroid*/); group("iosOnNavigationResponse", () { testWidgets('allow navigation', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); final Completer onNavigationResponseCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), initialOptions: InAppWebViewGroupOptions( ios: IOSInAppWebViewOptions(useOnNavigationResponse: true)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, iosOnNavigationResponse: (controller, navigationResponse) async { onNavigationResponseCompleter .complete(navigationResponse.response!.url.toString()); return IOSNavigationResponseAction.ALLOW; }, ), ), ); await pageLoaded.future; final String url = await onNavigationResponseCompleter.future; expect(url, 'https://flutter.dev/'); }, skip: !Platform.isIOS); testWidgets('cancel navigation', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); final Completer onNavigationResponseCompleter = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), initialOptions: InAppWebViewGroupOptions( ios: IOSInAppWebViewOptions(useOnNavigationResponse: true)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, iosOnNavigationResponse: (controller, navigationResponse) async { onNavigationResponseCompleter .complete(navigationResponse.response!.url.toString()); return IOSNavigationResponseAction.CANCEL; }, ), ), ); final String url = await onNavigationResponseCompleter.future; expect(url, 'https://flutter.dev/'); expect(pageLoaded.future, doesNotComplete); }, skip: !Platform.isIOS); }, skip: !Platform.isIOS); testWidgets('initialUserScripts', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), initialUserScripts: UnmodifiableListView([ UserScript( source: "var foo = 49;", injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START), UserScript( source: "var foo2 = 19;", injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START, contentWorld: ContentWorld.PAGE), UserScript( source: "var bar = 2;", injectionTime: UserScriptInjectionTime.AT_DOCUMENT_END, contentWorld: ContentWorld.DEFAULT_CLIENT), UserScript( source: "var bar2 = 12;", injectionTime: UserScriptInjectionTime.AT_DOCUMENT_END, contentWorld: ContentWorld.world(name: "test")), ]), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) async { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; expect(await controller.evaluateJavascript(source: "foo;"), 49); expect(await controller.evaluateJavascript(source: "foo2;"), 19); expect( await controller.evaluateJavascript( source: "foo2;", contentWorld: ContentWorld.PAGE), 19); expect(await controller.evaluateJavascript(source: "bar;"), isNull); expect(await controller.evaluateJavascript(source: "bar2;"), isNull); expect( await controller.evaluateJavascript( source: "bar;", contentWorld: ContentWorld.DEFAULT_CLIENT), 2); expect( await controller.evaluateJavascript( source: "bar2;", contentWorld: ContentWorld.world(name: "test")), 12); }); group('POST requests', () { testWidgets('initialUrlRequest', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer postPageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest( url: Uri.parse( "http://${environment["NODE_SERVER_IP"]}:8082/test-post"), method: 'POST', body: Uint8List.fromList(utf8.encode("name=FooBar")), headers: { 'Content-Type': 'application/x-www-form-urlencoded' }), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { postPageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await postPageLoaded.future; final String? currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, 'http://${environment["NODE_SERVER_IP"]}:8082/test-post'); final String? pContent = await controller.evaluateJavascript( source: "document.querySelector('p').innerHTML;"); expect(pContent, "HELLO FooBar!"); }); testWidgets('loadUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer postPageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { if (url?.scheme != "about") { postPageLoaded.complete(); } }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; var postData = Uint8List.fromList(utf8.encode("name=FooBar")); await controller.loadUrl( urlRequest: URLRequest( url: Uri.parse( "http://${environment["NODE_SERVER_IP"]}:8082/test-post"), method: 'POST', body: postData, headers: { 'Content-Type': 'application/x-www-form-urlencoded' })); await postPageLoaded.future; final String? currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, 'http://${environment["NODE_SERVER_IP"]}:8082/test-post'); final String? pContent = await controller.evaluateJavascript( source: "document.querySelector('p').innerHTML;"); expect(pContent, "HELLO FooBar!"); }); testWidgets('postUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer postPageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { if (url?.scheme != "about") { postPageLoaded.complete(); } }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; var postData = Uint8List.fromList(utf8.encode("name=FooBar")); await controller.postUrl( url: Uri.parse( "http://${environment["NODE_SERVER_IP"]}:8082/test-post"), postData: postData); await postPageLoaded.future; final String? currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, 'http://${environment["NODE_SERVER_IP"]}:8082/test-post'); final String? pContent = await controller.evaluateJavascript( source: "document.querySelector('p').innerHTML;"); expect(pContent, "HELLO FooBar!"); }); }); testWidgets('loadData', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoads.stream.first; await controller.loadData( data: """ placeholder 100x50 """, encoding: 'utf-8', mimeType: 'text/html', androidHistoryUrl: Uri.parse("https://flutter.dev"), baseUrl: Uri.parse("https://flutter.dev")); await pageLoads.stream.first; final String? currentUrl = (await controller.getUrl())?.toString(); expect(currentUrl, 'https://flutter.dev/'); pageLoads.close(); }); testWidgets('loadFile', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoads.stream.first; await controller.loadFile( assetFilePath: "test_assets/in_app_webview_initial_file_test.html"); await pageLoads.stream.first; final Uri? url = await controller.getUrl(); expect(url, isNotNull); expect(url!.scheme, 'file'); expect(url.path, endsWith("test_assets/in_app_webview_initial_file_test.html")); pageLoads.close(); }); testWidgets('reload', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; String? url = await pageLoads.stream.first; expect(url, 'https://flutter.dev/'); await controller.reload(); url = await pageLoads.stream.first; expect(url, 'https://flutter.dev/'); pageLoads.close(); }); testWidgets('web history - go back and forward', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; var url = await pageLoads.stream.first; var webHistory = await controller.getCopyBackForwardList(); expect(url, 'https://flutter.dev/'); expect(webHistory!.currentIndex, 0); expect(webHistory.list!.length, 1); expect(webHistory.list![0].url.toString(), 'https://flutter.dev/'); await controller.loadUrl( urlRequest: URLRequest(url: Uri.parse('https://github.com/flutter'))); url = await pageLoads.stream.first; webHistory = await controller.getCopyBackForwardList(); expect(url, 'https://github.com/flutter'); expect(await controller.canGoBack(), true); expect(await controller.canGoForward(), false); expect(await controller.canGoBackOrForward(steps: -1), true); expect(await controller.canGoBackOrForward(steps: 1), false); expect(webHistory!.currentIndex, 1); expect(webHistory.list!.length, 2); expect(webHistory.list![0].url.toString(), 'https://flutter.dev/'); expect(webHistory.list![1].url.toString(), 'https://github.com/flutter'); await controller.goBack(); url = await pageLoads.stream.first; webHistory = await controller.getCopyBackForwardList(); expect(url, 'https://flutter.dev/'); expect(await controller.canGoBack(), false); expect(await controller.canGoForward(), true); expect(await controller.canGoBackOrForward(steps: -1), false); expect(await controller.canGoBackOrForward(steps: 1), true); expect(webHistory!.currentIndex, 0); expect(webHistory.list!.length, 2); expect(webHistory.list![0].url.toString(), 'https://flutter.dev/'); expect(webHistory.list![1].url.toString(), 'https://github.com/flutter'); await controller.goForward(); url = await pageLoads.stream.first; webHistory = await controller.getCopyBackForwardList(); expect(url, 'https://github.com/flutter'); expect(await controller.canGoBack(), true); expect(await controller.canGoForward(), false); expect(await controller.canGoBackOrForward(steps: -1), true); expect(await controller.canGoBackOrForward(steps: 1), false); expect(webHistory!.currentIndex, 1); expect(webHistory.list!.length, 2); expect(webHistory.list![0].url.toString(), 'https://flutter.dev/'); expect(webHistory.list![1].url.toString(), 'https://github.com/flutter'); await controller.goTo(historyItem: webHistory.list![0]); url = await pageLoads.stream.first; webHistory = await controller.getCopyBackForwardList(); expect(url, 'https://flutter.dev/'); expect(await controller.canGoBack(), false); expect(await controller.canGoForward(), true); expect(await controller.canGoBackOrForward(steps: -1), false); expect(await controller.canGoBackOrForward(steps: 1), true); expect(webHistory!.currentIndex, 0); expect(webHistory.list!.length, 2); expect(webHistory.list![0].url.toString(), 'https://flutter.dev/'); expect(webHistory.list![1].url.toString(), 'https://github.com/flutter'); pageLoads.close(); }); testWidgets('getProgress', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; final int? progress = await controller.getProgress(); expect(progress, 100); }); testWidgets('getHtml', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; final String? html = await controller.getHtml(); expect(html, isNotNull); }); testWidgets('getFavicons', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; final List? favicons = await controller.getFavicons(); expect(favicons, isNotNull); expect(favicons, isNotEmpty); }); testWidgets('isLoading', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageStarted = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions(clearCache: true)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStart: (controller, url) { pageStarted.complete(); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageStarted.future; expect(await controller.isLoading(), true); await pageLoaded.future; expect(await controller.isLoading(), false); }); testWidgets('stopLoading', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions(clearCache: true)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStart: (controller, url) { controller.stopLoading(); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; if (Platform.isAndroid) { await pageLoaded.future; expect(await controller.evaluateJavascript(source: "document.body"), isNull); } else if (Platform.isIOS) { expect(pageLoaded.future, doesNotComplete); } }); testWidgets('injectJavascriptFileFromUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.injectJavascriptFileFromUrl( urlFile: Uri.parse('https://code.jquery.com/jquery-3.3.1.min.js'), scriptHtmlTagAttributes: ScriptHtmlTagAttributes(id: 'jquery')); await Future.delayed(Duration(seconds: 2)); expect( await controller.evaluateJavascript( source: "document.body.querySelector('#jquery') == null;"), false); expect( await controller.evaluateJavascript(source: "window.jQuery == null;"), false); }); testWidgets('injectJavascriptFileFromAsset', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.injectJavascriptFileFromAsset( assetFilePath: 'test_assets/js/jquery-3.3.1.min.js'); expect( await controller.evaluateJavascript(source: "window.jQuery == null;"), false); }); testWidgets('injectCSSCode', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.injectCSSCode(source: """ body { background-color: rgb(0, 0, 255); } """); String? backgroundColor = await controller.evaluateJavascript(source: """ var element = document.body; var style = getComputedStyle(element); style.backgroundColor; """); expect(backgroundColor, 'rgb(0, 0, 255)'); }); testWidgets('injectCSSFileFromUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.injectCSSFileFromUrl( urlFile: Uri.parse( 'https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css'), cssLinkHtmlTagAttributes: CSSLinkHtmlTagAttributes(id: 'bootstrap')); await Future.delayed(Duration(seconds: 2)); expect( await controller.evaluateJavascript( source: "document.head.querySelector('#bootstrap') == null;"), false); }); testWidgets('injectCSSFileFromAsset', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.injectCSSFileFromAsset( assetFilePath: 'test_assets/css/blue-body.css'); String? backgroundColor = await controller.evaluateJavascript(source: """ var element = document.body; var style = getComputedStyle(element); style.backgroundColor; """); expect(backgroundColor, 'rgb(0, 0, 255)'); }); testWidgets('takeScreenshot', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; var screenshotConfiguration = ScreenshotConfiguration( compressFormat: CompressFormat.JPEG, quality: 20, rect: InAppWebViewRect(width: 100, height: 100, x: 50, y: 50)); var screenshot = await controller.takeScreenshot( screenshotConfiguration: screenshotConfiguration); expect(screenshot, isNotNull); }); testWidgets('clearCache', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await expectLater(controller.clearCache(), completes); }); testWidgets('T-Rex Runner game', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; var html = await controller.getTRexRunnerHtml(); var css = await controller.getTRexRunnerCss(); expect(html, isNotNull); expect(css, isNotNull); }); testWidgets('pause/resume timers', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('about:blank')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await controller.evaluateJavascript(source: """ var count = 0; setInterval(function() { count = count + 10; }, 20); """); await controller.pauseTimers(); await Future.delayed(Duration(seconds: 2)); await controller.resumeTimers(); expect( await controller.evaluateJavascript(source: "count;"), lessThan(50)); await Future.delayed(Duration(seconds: 4)); expect(await controller.evaluateJavascript(source: "count;"), greaterThan(50)); }); testWidgets('printCurrentPage', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await expectLater(controller.printCurrentPage(), completes); }, skip: true); testWidgets('getContentHeight', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; final contentHeight = await controller.getContentHeight(); expect(contentHeight, isNonZero); expect(contentHeight, isPositive); }); testWidgets('zoomBy', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await expectLater( controller.zoomBy(zoomFactor: 3.0, iosAnimated: true), completes); }); testWidgets('getScale', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; final scale = await controller.getScale(); expect(scale, isNonZero); expect(scale, isPositive); }); testWidgets('clearFocus', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await expectLater(controller.clearFocus(), completes); }); testWidgets('requestFocusNodeHref', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await expectLater(controller.requestFocusNodeHref(), completes); }); testWidgets('requestImageRef', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await expectLater(controller.requestImageRef(), completes); }); testWidgets('getMetaTags', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; List metaTags = await controller.getMetaTags(); expect(metaTags, isNotEmpty); }); testWidgets('getMetaThemeColor', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://github.com')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; expect(await controller.getMetaThemeColor(), isNotNull); }); testWidgets('getCertificate', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; var sslCertificate = await controller.getCertificate(); expect(sslCertificate, isNotNull); expect(sslCertificate!.x509Certificate, isNotNull); expect(sslCertificate.issuedBy, isNotNull); expect(sslCertificate.issuedTo, isNotNull); expect(sslCertificate.validNotAfterDate, isNotNull); expect(sslCertificate.validNotBeforeDate, isNotNull); }); testWidgets('add/remove user scripts', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoads.stream.first; var userScript1 = UserScript( source: "window.foo = 49;", injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START); var userScript2 = UserScript( source: "window.bar = 19;", injectionTime: UserScriptInjectionTime.AT_DOCUMENT_END); await controller.addUserScripts(userScripts: [userScript1, userScript2]); await controller.reload(); await pageLoads.stream.first; var value = await controller.evaluateJavascript(source: "window.foo;"); expect(value, 49); value = await controller.evaluateJavascript(source: "window.bar;"); expect(value, 19); await controller.removeUserScript(userScript: userScript1); await controller.reload(); await pageLoads.stream.first; value = await controller.evaluateJavascript(source: "window.foo;"); expect(value, isNull); value = await controller.evaluateJavascript(source: "window.bar;"); expect(value, 19); await controller.removeAllUserScripts(); await controller.reload(); await pageLoads.stream.first; value = await controller.evaluateJavascript(source: "window.foo;"); expect(value, isNull); value = await controller.evaluateJavascript(source: "window.bar;"); expect(value, isNull); pageLoads.close(); }); testWidgets('saveWebArchive', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://github.com/flutter')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; // wait a little bit after page load otherwise Android will not save the web archive await Future.delayed(Duration(seconds: 1)); var supportDir = await getApplicationSupportDirectory(); var fileName = "flutter-website."; if (Platform.isAndroid) { fileName = fileName + WebArchiveFormat.MHT.toValue(); } else if (Platform.isIOS) { fileName = fileName + WebArchiveFormat.WEBARCHIVE.toValue(); } var fullPath = supportDir!.path + Platform.pathSeparator + fileName; var path = await controller.saveWebArchive(filePath: fullPath); expect(path, isNotNull); expect(path, endsWith(fileName)); path = await controller.saveWebArchive( filePath: supportDir.path, autoname: true); expect(path, isNotNull); }); testWidgets('isSecureContext', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoads.stream.first; expect(await controller.isSecureContext(), true); await controller.loadUrl( urlRequest: URLRequest(url: Uri.parse('http://example.com/'))); await pageLoads.stream.first; expect(await controller.isSecureContext(), false); pageLoads.close(); }); test('getDefaultUserAgent', () async { expect(await InAppWebViewController.getDefaultUserAgent(), isNotNull); }); group('android methods', () { testWidgets('clearSslPreferences', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await expectLater(controller.android.clearSslPreferences(), completes); }, skip: !Platform.isAndroid); testWidgets('pause/resume', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await expectLater(controller.android.pause(), completes); await Future.delayed(Duration(seconds: 1)); await expectLater(controller.android.resume(), completes); }, skip: !Platform.isAndroid); testWidgets('getOriginalUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; var originUrl = (await controller.android.getOriginalUrl())?.toString(); expect(originUrl, 'https://flutter.dev/'); }, skip: !Platform.isAndroid); testWidgets('pageDown/pageUp', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; expect(await controller.android.pageDown(bottom: false), true); await Future.delayed(Duration(seconds: 1)); expect(await controller.android.pageUp(top: false), true); }, skip: !Platform.isAndroid); testWidgets('zoomIn/zoomOut', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; expect(await controller.android.zoomIn(), true); await Future.delayed(Duration(seconds: 1)); expect(await controller.android.zoomOut(), true); }, skip: !Platform.isAndroid); testWidgets('clearHistory', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = StreamController.broadcast(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoads.add(url!.toString()); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoads.stream.first; await controller.loadUrl( urlRequest: URLRequest(url: Uri.parse('https://github.com/flutter'))); await pageLoads.stream.first; var webHistory = await controller.getCopyBackForwardList(); expect(webHistory!.list!.length, 2); await controller.android.clearHistory(); webHistory = await controller.getCopyBackForwardList(); expect(webHistory!.list!.length, 1); pageLoads.close(); }, skip: !Platform.isAndroid); test('clearClientCertPreferences', () async { await expectLater( AndroidInAppWebViewController.clearClientCertPreferences(), completes); }, skip: !Platform.isAndroid); test('getSafeBrowsingPrivacyPolicyUrl', () async { expect( await AndroidInAppWebViewController .getSafeBrowsingPrivacyPolicyUrl(), isNotNull); }, skip: !Platform.isAndroid); test('setSafeBrowsingWhitelist', () async { expect( await AndroidInAppWebViewController.setSafeBrowsingWhitelist( hosts: ["flutter.dev", "github.com"]), true); }, skip: !Platform.isAndroid); test('getCurrentWebViewPackage', () async { expect(await AndroidInAppWebViewController.getCurrentWebViewPackage(), isNotNull); }, skip: !Platform.isAndroid); }, skip: !Platform.isAndroid); group('ios methods', () { testWidgets('reloadFromOrigin', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; await expectLater(controller.ios.reloadFromOrigin(), completes); }, skip: !Platform.isIOS); testWidgets('createPdf', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; var iosWKPdfConfiguration = IOSWKPDFConfiguration( rect: InAppWebViewRect(width: 100, height: 100, x: 50, y: 50)); var pdf = await controller.ios .createPdf(iosWKPdfConfiguration: iosWKPdfConfiguration); expect(pdf, isNotNull); }, skip: !Platform.isIOS); testWidgets('createWebArchiveData', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { pageLoaded.complete(); }, ), ), ); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; expect(await controller.ios.createWebArchiveData(), isNotNull); }, skip: !Platform.isIOS); test('handlesURLScheme', () async { expect(await IOSInAppWebViewController.handlesURLScheme("http"), true); expect(await IOSInAppWebViewController.handlesURLScheme("https"), true); }, skip: !Platform.isIOS); }, skip: !Platform.isIOS); }); group('Cookie Manager', () { testWidgets('set, get, delete', (WidgetTester tester) async { CookieManager cookieManager = CookieManager.instance(); final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: InAppWebView( key: GlobalKey(), initialUrlRequest: URLRequest(url: Uri.parse('https://flutter.dev/')), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( clearCache: true, )), onLoadStop: (controller, url) { pageLoaded.complete(url!.toString()); }, ), ), ); final url = Uri.parse(await pageLoaded.future); await cookieManager.setCookie( url: url, name: "myCookie", value: "myValue"); List cookies = await cookieManager.getCookies(url: url); expect(cookies, isNotEmpty); Cookie? cookie = await cookieManager.getCookie(url: url, name: "myCookie"); expect(cookie?.value.toString(), "myValue"); await cookieManager.deleteCookie(url: url, name: "myCookie"); cookie = await cookieManager.getCookie(url: url, name: "myCookie"); expect(cookie, isNull); await cookieManager.deleteCookies(url: url); cookies = await cookieManager.getCookies(url: url); expect(cookies, isEmpty); }); }); group('HeadlessInAppWebView', () { test('run and dispose', () async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); var headlessWebView = new HeadlessInAppWebView( initialUrlRequest: URLRequest(url: Uri.parse("https://flutter.dev")), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) async { pageLoaded.complete(); }, ); await headlessWebView.run(); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; final String? url = (await controller.getUrl())?.toString(); expect(url, 'https://flutter.dev/'); await headlessWebView.dispose(); expect(() async => await headlessWebView.webViewController.getUrl(), throwsA(isInstanceOf())); }); test('set/get options', () async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); var headlessWebView = new HeadlessInAppWebView( initialUrlRequest: URLRequest(url: Uri.parse("https://flutter.dev")), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions(javaScriptEnabled: false)), onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) async { pageLoaded.complete(); }, ); await headlessWebView.run(); final InAppWebViewController controller = await controllerCompleter.future; await pageLoaded.future; InAppWebViewGroupOptions? options = await controller.getOptions(); expect(options, isNotNull); expect(options!.crossPlatform.javaScriptEnabled, false); await controller.setOptions( options: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions(javaScriptEnabled: true))); options = await controller.getOptions(); expect(options, isNotNull); expect(options!.crossPlatform.javaScriptEnabled, true); }); }); group('InAppBrowser', () { test('open and close', () async { var inAppBrowser = new MyInAppBrowser(); expect(inAppBrowser.isOpened(), false); expect(() async { await inAppBrowser.show(); }, throwsA(isInstanceOf())); await inAppBrowser.openUrlRequest( urlRequest: URLRequest(url: Uri.parse("https://flutter.dev"))); await inAppBrowser.browserCreated.future; expect(inAppBrowser.isOpened(), true); expect(() async { await inAppBrowser.openUrlRequest( urlRequest: URLRequest(url: Uri.parse("https://github.com/flutter"))); }, throwsA(isInstanceOf())); await inAppBrowser.firstPageLoaded.future; var controller = inAppBrowser.webViewController; final String? url = (await controller.getUrl())?.toString(); expect(url, 'https://flutter.dev/'); await inAppBrowser.close(); expect(inAppBrowser.isOpened(), false); expect(() async => await inAppBrowser.webViewController.getUrl(), throwsA(isInstanceOf())); }); test('set/get options', () async { var inAppBrowser = new MyInAppBrowser(); await inAppBrowser.openUrlRequest( urlRequest: URLRequest(url: Uri.parse("https://flutter.dev")), options: InAppBrowserClassOptions( crossPlatform: InAppBrowserOptions(hideToolbarTop: true))); await inAppBrowser.browserCreated.future; await inAppBrowser.firstPageLoaded.future; InAppBrowserClassOptions? options = await inAppBrowser.getOptions(); expect(options, isNotNull); expect(options!.crossPlatform.hideToolbarTop, true); await inAppBrowser.setOptions( options: InAppBrowserClassOptions( crossPlatform: InAppBrowserOptions(hideToolbarTop: false))); options = await inAppBrowser.getOptions(); expect(options, isNotNull); expect(options!.crossPlatform.hideToolbarTop, false); }); }); group('ChromeSafariBrowser', () { test('open and close', () async { var chromeSafariBrowser = new MyChromeSafariBrowser(); expect(chromeSafariBrowser.isOpened(), false); await chromeSafariBrowser.open(url: Uri.parse("https://flutter.dev")); await chromeSafariBrowser.browserCreated.future; expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open( url: Uri.parse("https://github.com/flutter")); }, throwsA(isInstanceOf())); await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.close(); await chromeSafariBrowser.browserClosed.future; expect(chromeSafariBrowser.isOpened(), false); }); }); }