| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726 |
- // Copyright 2019, the Chromium project authors. Please see the AUTHORS file
- // for details. All rights reserved. Use of this source code is governed by a
- // BSD-style license that can be found in the LICENSE file.
- import 'dart:async';
- import 'dart:convert';
- import 'dart:typed_data';
- import 'package:flutter/foundation.dart';
- import 'package:flutter/services.dart';
- import 'package:flutter/widgets.dart';
- import 'package:flutter_test/flutter_test.dart';
- import 'package:webview_flutter/webview_flutter.dart';
- import 'package:e2e/e2e.dart';
- void main() {
- E2EWidgetsFlutterBinding.ensureInitialized();
- testWidgets('initalUrl', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: 'https://flutter.dev/',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- final String currentUrl = await controller.currentUrl();
- expect(currentUrl, 'https://flutter.dev/');
- });
- testWidgets('loadUrl', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: 'https://flutter.dev/',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- await controller.loadUrl('https://www.google.com/');
- final String currentUrl = await controller.currentUrl();
- expect(currentUrl, 'https://www.google.com/');
- });
- // enable this once https://github.com/flutter/flutter/issues/31510
- // is resolved.
- testWidgets('loadUrl with headers', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final StreamController<String> pageStarts = StreamController<String>();
- final StreamController<String> pageLoads = StreamController<String>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: 'https://flutter.dev/',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageStarted: (String url) {
- pageStarts.add(url);
- },
- onPageFinished: (String url) {
- pageLoads.add(url);
- },
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- final Map<String, String> headers = <String, String>{
- 'test_header': 'flutter_test_header'
- };
- await controller.loadUrl('https://flutter-header-echo.herokuapp.com/',
- headers: headers);
- final String currentUrl = await controller.currentUrl();
- 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('document.documentElement.innerText');
- expect(content.contains('flutter_test_header'), isTrue);
- });
- testWidgets('JavaScriptChannel', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final Completer<void> pageStarted = Completer<void>();
- final Completer<void> pageLoaded = Completer<void>();
- final List<String> messagesReceived = <String>[];
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- // This is the data URL for: '<!DOCTYPE html>'
- initialUrl:
- 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- // TODO(iskakaushik): Remove this when collection literals makes it to stable.
- // ignore: prefer_collection_literals
- javascriptChannels: <JavascriptChannel>[
- JavascriptChannel(
- name: 'Echo',
- onMessageReceived: (JavascriptMessage message) {
- messagesReceived.add(message.message);
- },
- ),
- ].toSet(),
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- await pageStarted.future;
- await pageLoaded.future;
- expect(messagesReceived, isEmpty);
- await controller.evaluateJavascript('Echo.postMessage("hello");');
- expect(messagesReceived, equals(<String>['hello']));
- });
- testWidgets('resize webview', (WidgetTester tester) async {
- final String resizeTest = '''
- <!DOCTYPE html><html>
- <head><title>Resize test</title>
- <script type="text/javascript">
- function onResize() {
- Resize.postMessage("resize");
- }
- function onLoad() {
- window.onresize = onResize;
- }
- </script>
- </head>
- <body onload="onLoad();" bgColor="blue">
- </body>
- </html>
- ''';
- final String resizeTestBase64 =
- base64Encode(const Utf8Encoder().convert(resizeTest));
- final Completer<void> resizeCompleter = Completer<void>();
- final Completer<void> pageStarted = Completer<void>();
- final Completer<void> pageLoaded = Completer<void>();
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final GlobalKey key = GlobalKey();
- final WebView webView = WebView(
- key: key,
- initialUrl: 'data:text/html;charset=utf-8;base64,$resizeTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- // TODO(iskakaushik): Remove this when collection literals makes it to stable.
- // ignore: prefer_collection_literals
- javascriptChannels: <JavascriptChannel>[
- JavascriptChannel(
- name: 'Resize',
- onMessageReceived: (JavascriptMessage message) {
- resizeCompleter.complete(true);
- },
- ),
- ].toSet(),
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- javascriptMode: JavascriptMode.unrestricted,
- );
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: Column(
- children: <Widget>[
- 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: <Widget>[
- SizedBox(
- width: 400,
- height: 400,
- child: webView,
- ),
- ],
- ),
- ),
- );
- await resizeCompleter.future;
- });
- testWidgets('set custom userAgent', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter1 =
- Completer<WebViewController>();
- final GlobalKey _globalKey = GlobalKey();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: _globalKey,
- initialUrl: 'about:blank',
- javascriptMode: JavascriptMode.unrestricted,
- userAgent: 'Custom_User_Agent1',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter1.complete(controller);
- },
- ),
- ),
- );
- final WebViewController controller1 = await controllerCompleter1.future;
- final String customUserAgent1 = await _getUserAgent(controller1);
- expect(customUserAgent1, 'Custom_User_Agent1');
- // rebuild the WebView with a different user agent.
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: _globalKey,
- initialUrl: 'about:blank',
- javascriptMode: JavascriptMode.unrestricted,
- userAgent: 'Custom_User_Agent2',
- ),
- ),
- );
- final String customUserAgent2 = await _getUserAgent(controller1);
- expect(customUserAgent2, 'Custom_User_Agent2');
- });
- testWidgets('use default platform userAgent after webView is rebuilt',
- (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final GlobalKey _globalKey = GlobalKey();
- // Build the webView with no user agent to get the default platform user agent.
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: _globalKey,
- initialUrl: 'https://flutter.dev/',
- javascriptMode: JavascriptMode.unrestricted,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- final String defaultPlatformUserAgent = await _getUserAgent(controller);
- // rebuild the WebView with a custom user agent.
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: _globalKey,
- initialUrl: 'about:blank',
- javascriptMode: JavascriptMode.unrestricted,
- userAgent: 'Custom_User_Agent',
- ),
- ),
- );
- final String customUserAgent = await _getUserAgent(controller);
- expect(customUserAgent, 'Custom_User_Agent');
- // rebuilds the WebView with no user agent.
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: _globalKey,
- initialUrl: 'about:blank',
- javascriptMode: JavascriptMode.unrestricted,
- ),
- ),
- );
- final String customUserAgent2 = await _getUserAgent(controller);
- expect(customUserAgent2, defaultPlatformUserAgent);
- });
- group('Media playback policy', () {
- String audioTestBase64;
- setUpAll(() async {
- final ByteData audioData =
- await rootBundle.load('assets/sample_audio.ogg');
- final String base64AudioData =
- base64Encode(Uint8List.view(audioData.buffer));
- final String audioTest = '''
- <!DOCTYPE html><html>
- <head><title>Audio auto play</title>
- <script type="text/javascript">
- function play() {
- var audio = document.getElementById("audio");
- audio.play();
- }
- function isPaused() {
- var audio = document.getElementById("audio");
- return audio.paused;
- }
- </script>
- </head>
- <body onload="play();">
- <audio controls id="audio">
- <source src="data:audio/ogg;charset=utf-8;base64,$base64AudioData">
- </audio>
- </body>
- </html>
- ''';
- audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest));
- });
- testWidgets('Auto media playback', (WidgetTester tester) async {
- Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- Completer<void> pageStarted = Completer<void>();
- Completer<void> pageLoaded = Completer<void>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
- ),
- ),
- );
- WebViewController controller = await controllerCompleter.future;
- await pageStarted.future;
- await pageLoaded.future;
- String isPaused = await controller.evaluateJavascript('isPaused();');
- expect(isPaused, _webviewBool(false));
- controllerCompleter = Completer<WebViewController>();
- pageStarted = Completer<void>();
- pageLoaded = Completer<void>();
- // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- initialMediaPlaybackPolicy:
- AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
- ),
- ),
- );
- controller = await controllerCompleter.future;
- await pageStarted.future;
- await pageLoaded.future;
- isPaused = await controller.evaluateJavascript('isPaused();');
- expect(isPaused, _webviewBool(true));
- });
- testWidgets('Changes to initialMediaPlaybackPolocy are ignored',
- (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- Completer<void> pageStarted = Completer<void>();
- Completer<void> pageLoaded = Completer<void>();
- final GlobalKey key = GlobalKey();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: key,
- initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- await pageStarted.future;
- await pageLoaded.future;
- String isPaused = await controller.evaluateJavascript('isPaused();');
- expect(isPaused, _webviewBool(false));
- pageStarted = Completer<void>();
- pageLoaded = Completer<void>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: key,
- initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- initialMediaPlaybackPolicy:
- AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
- ),
- ),
- );
- await controller.reload();
- await pageStarted.future;
- await pageLoaded.future;
- isPaused = await controller.evaluateJavascript('isPaused();');
- expect(isPaused, _webviewBool(false));
- });
- });
- testWidgets('getTitle', (WidgetTester tester) async {
- final String getTitleTest = '''
- <!DOCTYPE html><html>
- <head><title>Some title</title>
- </head>
- <body>
- </body>
- </html>
- ''';
- final String getTitleTestBase64 =
- base64Encode(const Utf8Encoder().convert(getTitleTest));
- final Completer<void> pageStarted = Completer<void>();
- final Completer<void> pageLoaded = Completer<void>();
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- await pageStarted.future;
- await pageLoaded.future;
- final String title = await controller.getTitle();
- expect(title, 'Some title');
- });
- group('NavigationDelegate', () {
- final String blankPage = "<!DOCTYPE html><head></head><body></body></html>";
- final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,' +
- base64Encode(const Utf8Encoder().convert(blankPage));
- testWidgets('can allow requests', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final StreamController<String> pageLoads =
- StreamController<String>.broadcast();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: blankPageEncoded,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- navigationDelegate: (NavigationRequest request) {
- return (request.url.contains('youtube.com'))
- ? NavigationDecision.prevent
- : NavigationDecision.navigate;
- },
- onPageFinished: (String url) => pageLoads.add(url),
- ),
- ),
- );
- await pageLoads.stream.first; // Wait for initial page load.
- final WebViewController controller = await controllerCompleter.future;
- await controller
- .evaluateJavascript('location.href = "https://www.google.com/"');
- await pageLoads.stream.first; // Wait for the next page load.
- final String currentUrl = await controller.currentUrl();
- expect(currentUrl, 'https://www.google.com/');
- });
- testWidgets('can block requests', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final StreamController<String> pageLoads =
- StreamController<String>.broadcast();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: blankPageEncoded,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- navigationDelegate: (NavigationRequest request) {
- return (request.url.contains('youtube.com'))
- ? NavigationDecision.prevent
- : NavigationDecision.navigate;
- },
- onPageFinished: (String url) => pageLoads.add(url),
- ),
- ),
- );
- await pageLoads.stream.first; // Wait for initial page load.
- final WebViewController controller = await controllerCompleter.future;
- await controller
- .evaluateJavascript('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.first
- .timeout(const Duration(milliseconds: 500), onTimeout: () => null);
- final String currentUrl = await controller.currentUrl();
- expect(currentUrl, isNot(contains('youtube.com')));
- });
- testWidgets('supports asynchronous decisions', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final StreamController<String> pageLoads =
- StreamController<String>.broadcast();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: blankPageEncoded,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- navigationDelegate: (NavigationRequest request) async {
- NavigationDecision decision = NavigationDecision.prevent;
- decision = await Future<NavigationDecision>.delayed(
- const Duration(milliseconds: 10),
- () => NavigationDecision.navigate);
- return decision;
- },
- onPageFinished: (String url) => pageLoads.add(url),
- ),
- ),
- );
- await pageLoads.stream.first; // Wait for initial page load.
- final WebViewController controller = await controllerCompleter.future;
- await controller
- .evaluateJavascript('location.href = "https://www.google.com"');
- await pageLoads.stream.first; // Wait for second page to load.
- final String currentUrl = await controller.currentUrl();
- expect(currentUrl, 'https://www.google.com/');
- });
- });
- testWidgets('launches with gestureNavigationEnabled on iOS',
- (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: SizedBox(
- width: 400,
- height: 300,
- child: WebView(
- key: GlobalKey(),
- initialUrl: 'https://flutter.dev/',
- gestureNavigationEnabled: true,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- ),
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- final String currentUrl = await controller.currentUrl();
- expect(currentUrl, 'https://flutter.dev/');
- });
- testWidgets('target _blank opens in same window',
- (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final Completer<void> pageLoaded = Completer<void>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- await controller.evaluateJavascript('window.open("about:blank", "_blank")');
- await pageLoaded.future;
- final String currentUrl = await controller.currentUrl();
- expect(currentUrl, 'about:blank');
- });
- }
- // JavaScript booleans evaluate to different string values on Android and iOS.
- // This utility method returns the string boolean value of the current platform.
- String _webviewBool(bool value) {
- if (defaultTargetPlatform == TargetPlatform.iOS) {
- return value ? '1' : '0';
- }
- return value ? 'true' : 'false';
- }
- /// Returns the value used for the HTTP User-Agent: request header in subsequent HTTP requests.
- Future<String> _getUserAgent(WebViewController controller) async {
- if (defaultTargetPlatform == TargetPlatform.iOS) {
- return await controller.evaluateJavascript('navigator.userAgent;');
- }
- return jsonDecode(
- await controller.evaluateJavascript('navigator.userAgent;'));
- }
|