| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- import 'dart:math';
- import 'dart:typed_data';
- import 'package:flutter/services.dart';
- import 'package:flutter/src/foundation/basic_types.dart';
- import 'package:flutter/src/gestures/recognizer.dart';
- import 'package:flutter/widgets.dart';
- import 'package:flutter_test/flutter_test.dart';
- import 'package:webview_flutter/platform_interface.dart';
- import 'package:webview_flutter/webview_flutter.dart';
- typedef void VoidCallback();
- void main() {
- TestWidgetsFlutterBinding.ensureInitialized();
- final _FakePlatformViewsController fakePlatformViewsController =
- _FakePlatformViewsController();
- final _FakeCookieManager _fakeCookieManager = _FakeCookieManager();
- setUpAll(() {
- SystemChannels.platform_views.setMockMethodCallHandler(
- fakePlatformViewsController.fakePlatformViewsMethodHandler);
- SystemChannels.platform
- .setMockMethodCallHandler(_fakeCookieManager.onMethodCall);
- });
- setUp(() {
- fakePlatformViewsController.reset();
- _fakeCookieManager.reset();
- });
- testWidgets('Create WebView', (WidgetTester tester) async {
- await tester.pumpWidget(const WebView());
- });
- testWidgets('Initial url', (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://youtube.com',
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(await controller.currentUrl(), 'https://youtube.com');
- });
- testWidgets('Javascript mode', (WidgetTester tester) async {
- await tester.pumpWidget(const WebView(
- initialUrl: 'https://youtube.com',
- javascriptMode: JavascriptMode.unrestricted,
- ));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- expect(platformWebView.javascriptMode, JavascriptMode.unrestricted);
- await tester.pumpWidget(const WebView(
- initialUrl: 'https://youtube.com',
- javascriptMode: JavascriptMode.disabled,
- ));
- expect(platformWebView.javascriptMode, JavascriptMode.disabled);
- });
- testWidgets('Load url', (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- await controller.loadUrl('https://flutter.io');
- expect(await controller.currentUrl(), 'https://flutter.io');
- });
- testWidgets('Invalid urls', (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- expect(() => controller.loadUrl(null), throwsA(anything));
- expect(await controller.currentUrl(), isNull);
- expect(() => controller.loadUrl(''), throwsA(anything));
- expect(await controller.currentUrl(), isNull);
- // Missing schema.
- expect(() => controller.loadUrl('flutter.io'), throwsA(anything));
- expect(await controller.currentUrl(), isNull);
- });
- testWidgets('Headers in loadUrl', (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- final Map<String, String> headers = <String, String>{
- 'CACHE-CONTROL': 'ABC'
- };
- await controller.loadUrl('https://flutter.io', headers: headers);
- expect(await controller.currentUrl(), equals('https://flutter.io'));
- });
- testWidgets("Can't go back before loading a page",
- (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- final bool canGoBackNoPageLoaded = await controller.canGoBack();
- expect(canGoBackNoPageLoaded, false);
- });
- testWidgets("Clear Cache", (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- expect(fakePlatformViewsController.lastCreatedView.hasCache, true);
- await controller.clearCache();
- expect(fakePlatformViewsController.lastCreatedView.hasCache, false);
- });
- testWidgets("Can't go back with no history", (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://flutter.io',
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- final bool canGoBackFirstPageLoaded = await controller.canGoBack();
- expect(canGoBackFirstPageLoaded, false);
- });
- testWidgets('Can go back', (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://flutter.io',
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- await controller.loadUrl('https://www.google.com');
- final bool canGoBackSecondPageLoaded = await controller.canGoBack();
- expect(canGoBackSecondPageLoaded, true);
- });
- testWidgets("Can't go forward before loading a page",
- (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- final bool canGoForwardNoPageLoaded = await controller.canGoForward();
- expect(canGoForwardNoPageLoaded, false);
- });
- testWidgets("Can't go forward with no history", (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://flutter.io',
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- final bool canGoForwardFirstPageLoaded = await controller.canGoForward();
- expect(canGoForwardFirstPageLoaded, false);
- });
- testWidgets('Can go forward', (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://flutter.io',
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- await controller.loadUrl('https://youtube.com');
- await controller.goBack();
- final bool canGoForwardFirstPageBacked = await controller.canGoForward();
- expect(canGoForwardFirstPageBacked, true);
- });
- testWidgets('Go back', (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://youtube.com',
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- expect(await controller.currentUrl(), 'https://youtube.com');
- await controller.loadUrl('https://flutter.io');
- expect(await controller.currentUrl(), 'https://flutter.io');
- await controller.goBack();
- expect(await controller.currentUrl(), 'https://youtube.com');
- });
- testWidgets('Go forward', (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://youtube.com',
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- expect(await controller.currentUrl(), 'https://youtube.com');
- await controller.loadUrl('https://flutter.io');
- expect(await controller.currentUrl(), 'https://flutter.io');
- await controller.goBack();
- expect(await controller.currentUrl(), 'https://youtube.com');
- await controller.goForward();
- expect(await controller.currentUrl(), 'https://flutter.io');
- });
- testWidgets('Current URL', (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(controller, isNotNull);
- // Test a WebView without an explicitly set first URL.
- expect(await controller.currentUrl(), isNull);
- await controller.loadUrl('https://youtube.com');
- expect(await controller.currentUrl(), 'https://youtube.com');
- await controller.loadUrl('https://flutter.io');
- expect(await controller.currentUrl(), 'https://flutter.io');
- await controller.goBack();
- expect(await controller.currentUrl(), 'https://youtube.com');
- });
- testWidgets('Reload url', (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://flutter.io',
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- expect(platformWebView.currentUrl, 'https://flutter.io');
- expect(platformWebView.amountOfReloadsOnCurrentUrl, 0);
- await controller.reload();
- expect(platformWebView.currentUrl, 'https://flutter.io');
- expect(platformWebView.amountOfReloadsOnCurrentUrl, 1);
- await controller.loadUrl('https://youtube.com');
- expect(platformWebView.amountOfReloadsOnCurrentUrl, 0);
- });
- testWidgets('evaluate Javascript', (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://flutter.io',
- javascriptMode: JavascriptMode.unrestricted,
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(
- await controller.evaluateJavascript("fake js string"), "fake js string",
- reason: 'should get the argument');
- expect(
- () => controller.evaluateJavascript(null),
- throwsA(anything),
- );
- });
- testWidgets('evaluate Javascript with JavascriptMode disabled',
- (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://flutter.io',
- javascriptMode: JavascriptMode.disabled,
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- expect(
- () => controller.evaluateJavascript('fake js string'),
- throwsA(anything),
- );
- expect(
- () => controller.evaluateJavascript(null),
- throwsA(anything),
- );
- });
- testWidgets('Cookies can be cleared once', (WidgetTester tester) async {
- await tester.pumpWidget(
- const WebView(
- initialUrl: 'https://flutter.io',
- ),
- );
- final CookieManager cookieManager = CookieManager();
- final bool hasCookies = await cookieManager.clearCookies();
- expect(hasCookies, true);
- });
- testWidgets('Second cookie clear does not have cookies',
- (WidgetTester tester) async {
- await tester.pumpWidget(
- const WebView(
- initialUrl: 'https://flutter.io',
- ),
- );
- final CookieManager cookieManager = CookieManager();
- final bool hasCookies = await cookieManager.clearCookies();
- expect(hasCookies, true);
- final bool hasCookiesSecond = await cookieManager.clearCookies();
- expect(hasCookiesSecond, false);
- });
- testWidgets('Initial JavaScript channels', (WidgetTester tester) async {
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://youtube.com',
- // TODO(iskakaushik): Remove this when collection literals makes it to stable.
- // ignore: prefer_collection_literals
- javascriptChannels: <JavascriptChannel>[
- JavascriptChannel(
- name: 'Tts', onMessageReceived: (JavascriptMessage msg) {}),
- JavascriptChannel(
- name: 'Alarm', onMessageReceived: (JavascriptMessage msg) {}),
- ].toSet(),
- ),
- );
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- expect(platformWebView.javascriptChannelNames,
- unorderedEquals(<String>['Tts', 'Alarm']));
- });
- test('Only valid JavaScript channel names are allowed', () {
- final JavascriptMessageHandler noOp = (JavascriptMessage msg) {};
- JavascriptChannel(name: 'Tts1', onMessageReceived: noOp);
- JavascriptChannel(name: '_Alarm', onMessageReceived: noOp);
- JavascriptChannel(name: 'foo_bar_', onMessageReceived: noOp);
- VoidCallback createChannel(String name) {
- return () {
- JavascriptChannel(name: name, onMessageReceived: noOp);
- };
- }
- expect(createChannel('1Alarm'), throwsAssertionError);
- expect(createChannel('foo.bar'), throwsAssertionError);
- expect(createChannel(''), throwsAssertionError);
- });
- testWidgets('Unique JavaScript channel names are required',
- (WidgetTester tester) async {
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://youtube.com',
- // TODO(iskakaushik): Remove this when collection literals makes it to stable.
- // ignore: prefer_collection_literals
- javascriptChannels: <JavascriptChannel>[
- JavascriptChannel(
- name: 'Alarm', onMessageReceived: (JavascriptMessage msg) {}),
- JavascriptChannel(
- name: 'Alarm', onMessageReceived: (JavascriptMessage msg) {}),
- ].toSet(),
- ),
- );
- expect(tester.takeException(), isNot(null));
- });
- testWidgets('JavaScript channels update', (WidgetTester tester) async {
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://youtube.com',
- // TODO(iskakaushik): Remove this when collection literals makes it to stable.
- // ignore: prefer_collection_literals
- javascriptChannels: <JavascriptChannel>[
- JavascriptChannel(
- name: 'Tts', onMessageReceived: (JavascriptMessage msg) {}),
- JavascriptChannel(
- name: 'Alarm', onMessageReceived: (JavascriptMessage msg) {}),
- ].toSet(),
- ),
- );
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://youtube.com',
- // TODO(iskakaushik): Remove this when collection literals makes it to stable.
- // ignore: prefer_collection_literals
- javascriptChannels: <JavascriptChannel>[
- JavascriptChannel(
- name: 'Tts', onMessageReceived: (JavascriptMessage msg) {}),
- JavascriptChannel(
- name: 'Alarm2', onMessageReceived: (JavascriptMessage msg) {}),
- JavascriptChannel(
- name: 'Alarm3', onMessageReceived: (JavascriptMessage msg) {}),
- ].toSet(),
- ),
- );
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- expect(platformWebView.javascriptChannelNames,
- unorderedEquals(<String>['Tts', 'Alarm2', 'Alarm3']));
- });
- testWidgets('Remove all JavaScript channels and then add',
- (WidgetTester tester) async {
- // This covers a specific bug we had where after updating javascriptChannels to null,
- // updating it again with a subset of the previously registered channels fails as the
- // widget's cache of current channel wasn't properly updated when updating javascriptChannels to
- // null.
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://youtube.com',
- // TODO(iskakaushik): Remove this when collection literals makes it to stable.
- // ignore: prefer_collection_literals
- javascriptChannels: <JavascriptChannel>[
- JavascriptChannel(
- name: 'Tts', onMessageReceived: (JavascriptMessage msg) {}),
- ].toSet(),
- ),
- );
- await tester.pumpWidget(
- const WebView(
- initialUrl: 'https://youtube.com',
- ),
- );
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://youtube.com',
- // TODO(iskakaushik): Remove this when collection literals makes it to stable.
- // ignore: prefer_collection_literals
- javascriptChannels: <JavascriptChannel>[
- JavascriptChannel(
- name: 'Tts', onMessageReceived: (JavascriptMessage msg) {}),
- ].toSet(),
- ),
- );
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- expect(platformWebView.javascriptChannelNames,
- unorderedEquals(<String>['Tts']));
- });
- testWidgets('JavaScript channel messages', (WidgetTester tester) async {
- final List<String> ttsMessagesReceived = <String>[];
- final List<String> alarmMessagesReceived = <String>[];
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://youtube.com',
- // TODO(iskakaushik): Remove this when collection literals makes it to stable.
- // ignore: prefer_collection_literals
- javascriptChannels: <JavascriptChannel>[
- JavascriptChannel(
- name: 'Tts',
- onMessageReceived: (JavascriptMessage msg) {
- ttsMessagesReceived.add(msg.message);
- }),
- JavascriptChannel(
- name: 'Alarm',
- onMessageReceived: (JavascriptMessage msg) {
- alarmMessagesReceived.add(msg.message);
- }),
- ].toSet(),
- ),
- );
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- expect(ttsMessagesReceived, isEmpty);
- expect(alarmMessagesReceived, isEmpty);
- platformWebView.fakeJavascriptPostMessage('Tts', 'Hello');
- platformWebView.fakeJavascriptPostMessage('Tts', 'World');
- expect(ttsMessagesReceived, <String>['Hello', 'World']);
- });
- group('$PageStartedCallback', () {
- testWidgets('onPageStarted is not null', (WidgetTester tester) async {
- String returnedUrl;
- await tester.pumpWidget(WebView(
- initialUrl: 'https://youtube.com',
- onPageStarted: (String url) {
- returnedUrl = url;
- },
- ));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- platformWebView.fakeOnPageStartedCallback();
- expect(platformWebView.currentUrl, returnedUrl);
- });
- testWidgets('onPageStarted is null', (WidgetTester tester) async {
- await tester.pumpWidget(const WebView(
- initialUrl: 'https://youtube.com',
- onPageStarted: null,
- ));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- // The platform side will always invoke a call for onPageStarted. This is
- // to test that it does not crash on a null callback.
- platformWebView.fakeOnPageStartedCallback();
- });
- testWidgets('onPageStarted changed', (WidgetTester tester) async {
- String returnedUrl;
- await tester.pumpWidget(WebView(
- initialUrl: 'https://youtube.com',
- onPageStarted: (String url) {},
- ));
- await tester.pumpWidget(WebView(
- initialUrl: 'https://youtube.com',
- onPageStarted: (String url) {
- returnedUrl = url;
- },
- ));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- platformWebView.fakeOnPageStartedCallback();
- expect(platformWebView.currentUrl, returnedUrl);
- });
- });
- group('$PageFinishedCallback', () {
- testWidgets('onPageFinished is not null', (WidgetTester tester) async {
- String returnedUrl;
- await tester.pumpWidget(WebView(
- initialUrl: 'https://youtube.com',
- onPageFinished: (String url) {
- returnedUrl = url;
- },
- ));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- platformWebView.fakeOnPageFinishedCallback();
- expect(platformWebView.currentUrl, returnedUrl);
- });
- testWidgets('onPageFinished is null', (WidgetTester tester) async {
- await tester.pumpWidget(const WebView(
- initialUrl: 'https://youtube.com',
- onPageFinished: null,
- ));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- // The platform side will always invoke a call for onPageFinished. This is
- // to test that it does not crash on a null callback.
- platformWebView.fakeOnPageFinishedCallback();
- });
- testWidgets('onPageFinished changed', (WidgetTester tester) async {
- String returnedUrl;
- await tester.pumpWidget(WebView(
- initialUrl: 'https://youtube.com',
- onPageFinished: (String url) {},
- ));
- await tester.pumpWidget(WebView(
- initialUrl: 'https://youtube.com',
- onPageFinished: (String url) {
- returnedUrl = url;
- },
- ));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- platformWebView.fakeOnPageFinishedCallback();
- expect(platformWebView.currentUrl, returnedUrl);
- });
- });
- group('navigationDelegate', () {
- testWidgets('hasNavigationDelegate', (WidgetTester tester) async {
- await tester.pumpWidget(const WebView(
- initialUrl: 'https://youtube.com',
- ));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- expect(platformWebView.hasNavigationDelegate, false);
- await tester.pumpWidget(WebView(
- initialUrl: 'https://youtube.com',
- navigationDelegate: (NavigationRequest r) => null,
- ));
- expect(platformWebView.hasNavigationDelegate, true);
- });
- testWidgets('Block navigation', (WidgetTester tester) async {
- final List<NavigationRequest> navigationRequests = <NavigationRequest>[];
- await tester.pumpWidget(WebView(
- initialUrl: 'https://youtube.com',
- navigationDelegate: (NavigationRequest request) {
- navigationRequests.add(request);
- // Only allow navigating to https://flutter.dev
- return request.url == 'https://flutter.dev'
- ? NavigationDecision.navigate
- : NavigationDecision.prevent;
- }));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- expect(platformWebView.hasNavigationDelegate, true);
- platformWebView.fakeNavigate('https://www.google.com');
- // The navigation delegate only allows navigation to https://flutter.dev
- // so we should still be in https://youtube.com.
- expect(platformWebView.currentUrl, 'https://youtube.com');
- expect(navigationRequests.length, 1);
- expect(navigationRequests[0].url, 'https://www.google.com');
- expect(navigationRequests[0].isForMainFrame, true);
- platformWebView.fakeNavigate('https://flutter.dev');
- await tester.pump();
- expect(platformWebView.currentUrl, 'https://flutter.dev');
- });
- });
- group('debuggingEnabled', () {
- testWidgets('enable debugging', (WidgetTester tester) async {
- await tester.pumpWidget(const WebView(
- debuggingEnabled: true,
- ));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- expect(platformWebView.debuggingEnabled, true);
- });
- testWidgets('defaults to false', (WidgetTester tester) async {
- await tester.pumpWidget(const WebView());
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- expect(platformWebView.debuggingEnabled, false);
- });
- testWidgets('can be changed', (WidgetTester tester) async {
- final GlobalKey key = GlobalKey();
- await tester.pumpWidget(WebView(key: key));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- await tester.pumpWidget(WebView(
- key: key,
- debuggingEnabled: true,
- ));
- expect(platformWebView.debuggingEnabled, true);
- await tester.pumpWidget(WebView(
- key: key,
- debuggingEnabled: false,
- ));
- expect(platformWebView.debuggingEnabled, false);
- });
- });
- group('Custom platform implementation', () {
- setUpAll(() {
- WebView.platform = MyWebViewPlatform();
- });
- tearDownAll(() {
- WebView.platform = null;
- });
- testWidgets('creation', (WidgetTester tester) async {
- await tester.pumpWidget(
- const WebView(
- initialUrl: 'https://youtube.com',
- gestureNavigationEnabled: true,
- ),
- );
- final MyWebViewPlatform builder = WebView.platform;
- final MyWebViewPlatformController platform = builder.lastPlatformBuilt;
- expect(
- platform.creationParams,
- MatchesCreationParams(CreationParams(
- initialUrl: 'https://youtube.com',
- webSettings: WebSettings(
- javascriptMode: JavascriptMode.disabled,
- hasNavigationDelegate: false,
- debuggingEnabled: false,
- userAgent: WebSetting<String>.of(null),
- gestureNavigationEnabled: true,
- ),
- // TODO(iskakaushik): Remove this when collection literals makes it to stable.
- // ignore: prefer_collection_literals
- javascriptChannelNames: Set<String>(),
- )));
- });
- testWidgets('loadUrl', (WidgetTester tester) async {
- WebViewController controller;
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://youtube.com',
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
- final MyWebViewPlatform builder = WebView.platform;
- final MyWebViewPlatformController platform = builder.lastPlatformBuilt;
- final Map<String, String> headers = <String, String>{
- 'header': 'value',
- };
- await controller.loadUrl('https://google.com', headers: headers);
- expect(platform.lastUrlLoaded, 'https://google.com');
- expect(platform.lastRequestHeaders, headers);
- });
- });
- testWidgets('Set UserAgent', (WidgetTester tester) async {
- await tester.pumpWidget(const WebView(
- initialUrl: 'https://youtube.com',
- javascriptMode: JavascriptMode.unrestricted,
- ));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView;
- expect(platformWebView.userAgent, isNull);
- await tester.pumpWidget(const WebView(
- initialUrl: 'https://youtube.com',
- javascriptMode: JavascriptMode.unrestricted,
- userAgent: 'UA',
- ));
- expect(platformWebView.userAgent, 'UA');
- });
- }
- class FakePlatformWebView {
- FakePlatformWebView(int id, Map<dynamic, dynamic> params) {
- if (params.containsKey('initialUrl')) {
- final String initialUrl = params['initialUrl'];
- if (initialUrl != null) {
- history.add(initialUrl);
- currentPosition++;
- }
- }
- if (params.containsKey('javascriptChannelNames')) {
- javascriptChannelNames =
- List<String>.from(params['javascriptChannelNames']);
- }
- javascriptMode = JavascriptMode.values[params['settings']['jsMode']];
- hasNavigationDelegate =
- params['settings']['hasNavigationDelegate'] ?? false;
- debuggingEnabled = params['settings']['debuggingEnabled'];
- userAgent = params['settings']['userAgent'];
- channel = MethodChannel(
- 'plugins.flutter.io/webview_$id', const StandardMethodCodec());
- channel.setMockMethodCallHandler(onMethodCall);
- }
- MethodChannel channel;
- List<String> history = <String>[];
- int currentPosition = -1;
- int amountOfReloadsOnCurrentUrl = 0;
- bool hasCache = true;
- String get currentUrl => history.isEmpty ? null : history[currentPosition];
- JavascriptMode javascriptMode;
- List<String> javascriptChannelNames;
- bool hasNavigationDelegate;
- bool debuggingEnabled;
- String userAgent;
- Future<dynamic> onMethodCall(MethodCall call) {
- switch (call.method) {
- case 'loadUrl':
- final Map<dynamic, dynamic> request = call.arguments;
- _loadUrl(request['url']);
- return Future<void>.sync(() {});
- case 'updateSettings':
- if (call.arguments['jsMode'] != null) {
- javascriptMode = JavascriptMode.values[call.arguments['jsMode']];
- }
- if (call.arguments['hasNavigationDelegate'] != null) {
- hasNavigationDelegate = call.arguments['hasNavigationDelegate'];
- }
- if (call.arguments['debuggingEnabled'] != null) {
- debuggingEnabled = call.arguments['debuggingEnabled'];
- }
- userAgent = call.arguments['userAgent'];
- break;
- case 'canGoBack':
- return Future<bool>.sync(() => currentPosition > 0);
- break;
- case 'canGoForward':
- return Future<bool>.sync(() => currentPosition < history.length - 1);
- break;
- case 'goBack':
- currentPosition = max(-1, currentPosition - 1);
- return Future<void>.sync(() {});
- break;
- case 'goForward':
- currentPosition = min(history.length - 1, currentPosition + 1);
- return Future<void>.sync(() {});
- case 'reload':
- amountOfReloadsOnCurrentUrl++;
- return Future<void>.sync(() {});
- break;
- case 'currentUrl':
- return Future<String>.value(currentUrl);
- break;
- case 'evaluateJavascript':
- return Future<dynamic>.value(call.arguments);
- break;
- case 'addJavascriptChannels':
- final List<String> channelNames = List<String>.from(call.arguments);
- javascriptChannelNames.addAll(channelNames);
- break;
- case 'removeJavascriptChannels':
- final List<String> channelNames = List<String>.from(call.arguments);
- javascriptChannelNames
- .removeWhere((String channel) => channelNames.contains(channel));
- break;
- case 'clearCache':
- hasCache = false;
- return Future<void>.sync(() {});
- }
- return Future<void>.sync(() {});
- }
- void fakeJavascriptPostMessage(String jsChannel, String message) {
- final StandardMethodCodec codec = const StandardMethodCodec();
- final Map<String, dynamic> arguments = <String, dynamic>{
- 'channel': jsChannel,
- 'message': message
- };
- final ByteData data = codec
- .encodeMethodCall(MethodCall('javascriptChannelMessage', arguments));
- ServicesBinding.instance.defaultBinaryMessenger
- .handlePlatformMessage(channel.name, data, (ByteData data) {});
- }
- // Fakes a main frame navigation that was initiated by the webview, e.g when
- // the user clicks a link in the currently loaded page.
- void fakeNavigate(String url) {
- if (!hasNavigationDelegate) {
- print('no navigation delegate');
- _loadUrl(url);
- return;
- }
- final StandardMethodCodec codec = const StandardMethodCodec();
- final Map<String, dynamic> arguments = <String, dynamic>{
- 'url': url,
- 'isForMainFrame': true
- };
- final ByteData data =
- codec.encodeMethodCall(MethodCall('navigationRequest', arguments));
- ServicesBinding.instance.defaultBinaryMessenger
- .handlePlatformMessage(channel.name, data, (ByteData data) {
- final bool allow = codec.decodeEnvelope(data);
- if (allow) {
- _loadUrl(url);
- }
- });
- }
- void fakeOnPageStartedCallback() {
- final StandardMethodCodec codec = const StandardMethodCodec();
- final ByteData data = codec.encodeMethodCall(MethodCall(
- 'onPageStarted',
- <dynamic, dynamic>{'url': currentUrl},
- ));
- ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage(
- channel.name,
- data,
- (ByteData data) {},
- );
- }
- void fakeOnPageFinishedCallback() {
- final StandardMethodCodec codec = const StandardMethodCodec();
- final ByteData data = codec.encodeMethodCall(MethodCall(
- 'onPageFinished',
- <dynamic, dynamic>{'url': currentUrl},
- ));
- ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage(
- channel.name,
- data,
- (ByteData data) {},
- );
- }
- void _loadUrl(String url) {
- history = history.sublist(0, currentPosition + 1);
- history.add(url);
- currentPosition++;
- amountOfReloadsOnCurrentUrl = 0;
- }
- }
- class _FakePlatformViewsController {
- FakePlatformWebView lastCreatedView;
- Future<dynamic> fakePlatformViewsMethodHandler(MethodCall call) {
- switch (call.method) {
- case 'create':
- final Map<dynamic, dynamic> args = call.arguments;
- final Map<dynamic, dynamic> params = _decodeParams(args['params']);
- lastCreatedView = FakePlatformWebView(
- args['id'],
- params,
- );
- return Future<int>.sync(() => 1);
- default:
- return Future<void>.sync(() {});
- }
- }
- void reset() {
- lastCreatedView = null;
- }
- }
- Map<dynamic, dynamic> _decodeParams(Uint8List paramsMessage) {
- final ByteBuffer buffer = paramsMessage.buffer;
- final ByteData messageBytes = buffer.asByteData(
- paramsMessage.offsetInBytes,
- paramsMessage.lengthInBytes,
- );
- return const StandardMessageCodec().decodeMessage(messageBytes);
- }
- class _FakeCookieManager {
- _FakeCookieManager() {
- final MethodChannel channel = const MethodChannel(
- 'plugins.flutter.io/cookie_manager',
- StandardMethodCodec(),
- );
- channel.setMockMethodCallHandler(onMethodCall);
- }
- bool hasCookies = true;
- Future<bool> onMethodCall(MethodCall call) {
- switch (call.method) {
- case 'clearCookies':
- bool hadCookies = false;
- if (hasCookies) {
- hadCookies = true;
- hasCookies = false;
- }
- return Future<bool>.sync(() {
- return hadCookies;
- });
- break;
- }
- return Future<bool>.sync(() => null);
- }
- void reset() {
- hasCookies = true;
- }
- }
- class MyWebViewPlatform implements WebViewPlatform {
- MyWebViewPlatformController lastPlatformBuilt;
- @override
- Widget build({
- BuildContext context,
- CreationParams creationParams,
- @required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler,
- @required WebViewPlatformCreatedCallback onWebViewPlatformCreated,
- Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers,
- }) {
- assert(onWebViewPlatformCreated != null);
- lastPlatformBuilt = MyWebViewPlatformController(
- creationParams, gestureRecognizers, webViewPlatformCallbacksHandler);
- onWebViewPlatformCreated(lastPlatformBuilt);
- return Container();
- }
- @override
- Future<bool> clearCookies() {
- return Future<bool>.sync(() => null);
- }
- }
- class MyWebViewPlatformController extends WebViewPlatformController {
- MyWebViewPlatformController(this.creationParams, this.gestureRecognizers,
- WebViewPlatformCallbacksHandler platformHandler)
- : super(platformHandler);
- CreationParams creationParams;
- Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers;
- String lastUrlLoaded;
- Map<String, String> lastRequestHeaders;
- @override
- Future<void> loadUrl(String url, Map<String, String> headers) {
- equals(1, 1);
- lastUrlLoaded = url;
- lastRequestHeaders = headers;
- return null;
- }
- }
- class MatchesWebSettings extends Matcher {
- MatchesWebSettings(this._webSettings);
- final WebSettings _webSettings;
- @override
- Description describe(Description description) =>
- description.add('$_webSettings');
- @override
- bool matches(
- covariant WebSettings webSettings, Map<dynamic, dynamic> matchState) {
- return _webSettings.javascriptMode == webSettings.javascriptMode &&
- _webSettings.hasNavigationDelegate ==
- webSettings.hasNavigationDelegate &&
- _webSettings.debuggingEnabled == webSettings.debuggingEnabled &&
- _webSettings.gestureNavigationEnabled ==
- webSettings.gestureNavigationEnabled &&
- _webSettings.userAgent == webSettings.userAgent;
- }
- }
- class MatchesCreationParams extends Matcher {
- MatchesCreationParams(this._creationParams);
- final CreationParams _creationParams;
- @override
- Description describe(Description description) =>
- description.add('$_creationParams');
- @override
- bool matches(covariant CreationParams creationParams,
- Map<dynamic, dynamic> matchState) {
- return _creationParams.initialUrl == creationParams.initialUrl &&
- MatchesWebSettings(_creationParams.webSettings)
- .matches(creationParams.webSettings, matchState) &&
- orderedEquals(_creationParams.javascriptChannelNames)
- .matches(creationParams.javascriptChannelNames, matchState);
- }
- }
|