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 'in_app_webview/main.dart' as in_app_webview_test;
import '.env.dart';
import 'util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
if (defaultTargetPlatform == TargetPlatform.android) {
InAppWebViewController.setWebContentsDebuggingEnabled(true);
}
in_app_webview_test.main();
group('OLD InAppWebView', () {
// 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: defaultTargetPlatform != TargetPlatform.iOS);
//
// testWidgets(
// 'loadUrl with file:// scheme and allowingReadAccessTo 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}')),
// 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: defaultTargetPlatform != TargetPlatform.iOS);
// }, skip: defaultTargetPlatform != TargetPlatform.iOS);
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 /*defaultTargetPlatform != TargetPlatform.android*/);
});
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: defaultTargetPlatform != TargetPlatform.android);
}, skip: defaultTargetPlatform != TargetPlatform.android);
group('shouldOverrideUrlLoading', () {
final String page =
'''flutter_inappwebview