[webview_flutter] Update Widget Unit Tests to be platform agnostic (#4489)
diff --git a/packages/webview_flutter/webview_flutter/pubspec.yaml b/packages/webview_flutter/webview_flutter/pubspec.yaml
index b64e1b4..4450837 100644
--- a/packages/webview_flutter/webview_flutter/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter/pubspec.yaml
@@ -24,8 +24,10 @@
webview_flutter_wkwebview: ^2.2.0
dev_dependencies:
+ build_runner: ^2.1.5
flutter_driver:
sdk: flutter
flutter_test:
sdk: flutter
+ mockito: ^5.0.16
pedantic: ^1.10.0
diff --git a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart
index e325f68..69d4142 100644
--- a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart
@@ -2,37 +2,47 @@
// 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:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+import 'webview_flutter_test.mocks.dart';
+
typedef void VoidCallback();
+@GenerateMocks([WebViewPlatform, WebViewPlatformController])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
- final _FakePlatformViewsController fakePlatformViewsController =
- _FakePlatformViewsController();
-
- final _FakeCookieManager _fakeCookieManager = _FakeCookieManager();
-
- setUpAll(() {
- SystemChannels.platform_views.setMockMethodCallHandler(
- fakePlatformViewsController.fakePlatformViewsMethodHandler);
- SystemChannels.platform
- .setMockMethodCallHandler(_fakeCookieManager.onMethodCall);
- });
+ late MockWebViewPlatform mockWebViewPlatform;
+ late MockWebViewPlatformController mockWebViewPlatformController;
setUp(() {
- fakePlatformViewsController.reset();
- _fakeCookieManager.reset();
+ mockWebViewPlatformController = MockWebViewPlatformController();
+ mockWebViewPlatform = MockWebViewPlatform();
+ when(mockWebViewPlatform.build(
+ context: anyNamed('context'),
+ creationParams: anyNamed('creationParams'),
+ webViewPlatformCallbacksHandler:
+ anyNamed('webViewPlatformCallbacksHandler'),
+ javascriptChannelRegistry: anyNamed('javascriptChannelRegistry'),
+ onWebViewPlatformCreated: anyNamed('onWebViewPlatformCreated'),
+ gestureRecognizers: anyNamed('gestureRecognizers'),
+ )).thenAnswer((Invocation invocation) {
+ final WebViewPlatformCreatedCallback onWebViewPlatformCreated =
+ invocation.namedArguments[Symbol('onWebViewPlatformCreated')];
+ return TestPlatformWebView(
+ mockWebViewPlatformController: mockWebViewPlatformController,
+ onWebViewPlatformCreated: onWebViewPlatformCreated,
+ );
+ });
+
+ WebView.platform = mockWebViewPlatform;
});
testWidgets('Create WebView', (WidgetTester tester) async {
@@ -40,35 +50,41 @@
});
testWidgets('Initial url', (WidgetTester tester) async {
- late WebViewController controller;
- await tester.pumpWidget(
- WebView(
- initialUrl: 'https://youtube.com',
- onWebViewCreated: (WebViewController webViewController) {
- controller = webViewController;
- },
- ),
- );
+ await tester.pumpWidget(WebView(initialUrl: 'https://youtube.com'));
- expect(await controller.currentUrl(), 'https://youtube.com');
+ final CreationParams params = captureBuildArgs(
+ mockWebViewPlatform,
+ creationParams: true,
+ ).single;
+
+ expect(params.initialUrl, '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!;
+ final CreationParams unrestrictedparams = captureBuildArgs(
+ mockWebViewPlatform,
+ creationParams: true,
+ ).single;
- expect(platformWebView.javascriptMode, JavascriptMode.unrestricted);
+ expect(
+ unrestrictedparams.webSettings!.javascriptMode,
+ JavascriptMode.unrestricted,
+ );
await tester.pumpWidget(const WebView(
- initialUrl: 'https://youtube.com',
javascriptMode: JavascriptMode.disabled,
));
- expect(platformWebView.javascriptMode, JavascriptMode.disabled);
+
+ final CreationParams disabledparams = captureBuildArgs(
+ mockWebViewPlatform,
+ creationParams: true,
+ ).single;
+
+ expect(disabledparams.webSettings!.javascriptMode, JavascriptMode.disabled);
});
testWidgets('Load url', (WidgetTester tester) async {
@@ -85,7 +101,10 @@
await controller!.loadUrl('https://flutter.io');
- expect(await controller!.currentUrl(), 'https://flutter.io');
+ verify(mockWebViewPlatformController.loadUrl(
+ 'https://flutter.io',
+ argThat(isNull),
+ ));
});
testWidgets('Invalid urls', (WidgetTester tester) async {
@@ -100,14 +119,15 @@
expect(controller, isNotNull);
- expect(await controller!.currentUrl(), isNull);
+ final CreationParams params = captureBuildArgs(
+ mockWebViewPlatform,
+ creationParams: true,
+ ).single;
+
+ expect(params.initialUrl, 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 {
@@ -126,25 +146,11 @@
'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);
+ verify(mockWebViewPlatformController.loadUrl(
+ 'https://flutter.io',
+ <String, String>{'CACHE-CONTROL': 'ABC'},
+ ));
});
testWidgets("Clear Cache", (WidgetTester tester) async {
@@ -158,31 +164,16 @@
);
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);
+ verify(mockWebViewPlatformController.clearCache());
});
testWidgets('Can go back', (WidgetTester tester) async {
+ when(mockWebViewPlatformController.canGoBack())
+ .thenAnswer((_) => Future<bool>.value(true));
+
WebViewController? controller;
await tester.pumpWidget(
WebView(
@@ -194,15 +185,13 @@
);
expect(controller, isNotNull);
-
- await controller!.loadUrl('https://www.google.com');
- final bool canGoBackSecondPageLoaded = await controller!.canGoBack();
-
- expect(canGoBackSecondPageLoaded, true);
+ expect(controller!.canGoBack(), completion(true));
});
- testWidgets("Can't go forward before loading a page",
- (WidgetTester tester) async {
+ testWidgets("Can't go forward", (WidgetTester tester) async {
+ when(mockWebViewPlatformController.canGoForward())
+ .thenAnswer((_) => Future<bool>.value(false));
+
WebViewController? controller;
await tester.pumpWidget(
WebView(
@@ -213,47 +202,7 @@
);
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);
+ expect(controller!.canGoForward(), completion(false));
});
testWidgets('Go back', (WidgetTester tester) async {
@@ -267,17 +216,8 @@
),
);
- 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');
+ verify(mockWebViewPlatformController.goBack());
});
testWidgets('Go forward', (WidgetTester tester) async {
@@ -292,23 +232,14 @@
);
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');
+ verify(mockWebViewPlatformController.goForward());
});
testWidgets('Current URL', (WidgetTester tester) async {
+ when(mockWebViewPlatformController.currentUrl())
+ .thenAnswer((_) => Future<String>.value('https://youtube.com'));
+
WebViewController? controller;
await tester.pumpWidget(
WebView(
@@ -319,17 +250,6 @@
);
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');
});
@@ -344,23 +264,14 @@
),
);
- 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);
+ verify(mockWebViewPlatformController.reload());
});
testWidgets('evaluate Javascript', (WidgetTester tester) async {
+ when(mockWebViewPlatformController.evaluateJavascript('fake js string'))
+ .thenAnswer((_) => Future<String>.value('fake js string'));
+
late WebViewController controller;
await tester.pumpWidget(
WebView(
@@ -371,10 +282,11 @@
},
),
);
+
expect(
// ignore: deprecated_member_use_from_same_package
- await controller.evaluateJavascript("fake js string"),
- "fake js string",
+ await controller.evaluateJavascript('fake js string'),
+ 'fake js string',
reason: 'should get the argument');
});
@@ -409,8 +321,7 @@
),
);
await controller.runJavascript('fake js string');
- expect(fakePlatformViewsController.lastCreatedView?.lastRunJavaScriptString,
- 'fake js string');
+ verify(mockWebViewPlatformController.runJavascript('fake js string'));
});
testWidgets('runJavaScript with JavascriptMode disabled',
@@ -432,6 +343,10 @@
});
testWidgets('runJavaScriptReturningResult', (WidgetTester tester) async {
+ when(mockWebViewPlatformController
+ .runJavascriptReturningResult('fake js string'))
+ .thenAnswer((_) => Future<String>.value('fake js string'));
+
late WebViewController controller;
await tester.pumpWidget(
WebView(
@@ -442,8 +357,8 @@
},
),
);
- expect(await controller.runJavascriptReturningResult("fake js string"),
- "fake js string",
+ expect(await controller.runJavascriptReturningResult('fake js string'),
+ 'fake js string',
reason: 'should get the argument');
});
@@ -466,18 +381,9 @@
});
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);
- });
+ when(mockWebViewPlatform.clearCookies())
+ .thenAnswer((_) => Future<bool>.value(true));
- testWidgets('Second cookie clear does not have cookies',
- (WidgetTester tester) async {
await tester.pumpWidget(
const WebView(
initialUrl: 'https://flutter.io',
@@ -486,8 +392,6 @@
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 {
@@ -503,10 +407,12 @@
),
);
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final CreationParams params = captureBuildArgs(
+ mockWebViewPlatform,
+ creationParams: true,
+ ).single;
- expect(platformWebView.javascriptChannelNames,
+ expect(params.javascriptChannelNames,
unorderedEquals(<String>['Tts', 'Alarm']));
});
@@ -570,11 +476,15 @@
),
);
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final JavascriptChannelRegistry channelRegistry = captureBuildArgs(
+ mockWebViewPlatform,
+ javascriptChannelRegistry: true,
+ ).first;
- expect(platformWebView.javascriptChannelNames,
- unorderedEquals(<String>['Tts', 'Alarm2', 'Alarm3']));
+ expect(
+ channelRegistry.channels.keys,
+ unorderedEquals(<String>['Tts', 'Alarm2', 'Alarm3']),
+ );
});
testWidgets('Remove all JavaScript channels and then add',
@@ -609,11 +519,12 @@
),
);
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final JavascriptChannelRegistry channelRegistry = captureBuildArgs(
+ mockWebViewPlatform,
+ javascriptChannelRegistry: true,
+ ).last;
- expect(platformWebView.javascriptChannelNames,
- unorderedEquals(<String>['Tts']));
+ expect(channelRegistry.channels.keys, unorderedEquals(<String>['Tts']));
});
testWidgets('JavaScript channel messages', (WidgetTester tester) async {
@@ -637,14 +548,16 @@
),
);
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final JavascriptChannelRegistry channelRegistry = captureBuildArgs(
+ mockWebViewPlatform,
+ javascriptChannelRegistry: true,
+ ).single;
expect(ttsMessagesReceived, isEmpty);
expect(alarmMessagesReceived, isEmpty);
- platformWebView.fakeJavascriptPostMessage('Tts', 'Hello');
- platformWebView.fakeJavascriptPostMessage('Tts', 'World');
+ channelRegistry.onJavascriptChannelMessage('Tts', 'Hello');
+ channelRegistry.onJavascriptChannelMessage('Tts', 'World');
expect(ttsMessagesReceived, <String>['Hello', 'World']);
});
@@ -660,12 +573,14 @@
},
));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final WebViewPlatformCallbacksHandler handler = captureBuildArgs(
+ mockWebViewPlatform,
+ webViewPlatformCallbacksHandler: true,
+ ).single;
- platformWebView.fakeOnPageStartedCallback();
+ handler.onPageStarted('https://youtube.com');
- expect(platformWebView.currentUrl, returnedUrl);
+ expect(returnedUrl, 'https://youtube.com');
});
testWidgets('onPageStarted is null', (WidgetTester tester) async {
@@ -674,12 +589,14 @@
onPageStarted: null,
));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final WebViewPlatformCallbacksHandler handler = captureBuildArgs(
+ mockWebViewPlatform,
+ webViewPlatformCallbacksHandler: true,
+ ).single;
// 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();
+ handler.onPageStarted('https://youtube.com');
});
testWidgets('onPageStarted changed', (WidgetTester tester) async {
@@ -697,12 +614,13 @@
},
));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final WebViewPlatformCallbacksHandler handler = captureBuildArgs(
+ mockWebViewPlatform,
+ webViewPlatformCallbacksHandler: true,
+ ).last;
+ handler.onPageStarted('https://youtube.com');
- platformWebView.fakeOnPageStartedCallback();
-
- expect(platformWebView.currentUrl, returnedUrl);
+ expect(returnedUrl, 'https://youtube.com');
});
});
@@ -717,12 +635,13 @@
},
));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final WebViewPlatformCallbacksHandler handler = captureBuildArgs(
+ mockWebViewPlatform,
+ webViewPlatformCallbacksHandler: true,
+ ).single;
+ handler.onPageFinished('https://youtube.com');
- platformWebView.fakeOnPageFinishedCallback();
-
- expect(platformWebView.currentUrl, returnedUrl);
+ expect(returnedUrl, 'https://youtube.com');
});
testWidgets('onPageFinished is null', (WidgetTester tester) async {
@@ -731,12 +650,13 @@
onPageFinished: null,
));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
-
+ final WebViewPlatformCallbacksHandler handler = captureBuildArgs(
+ mockWebViewPlatform,
+ webViewPlatformCallbacksHandler: true,
+ ).single;
// 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();
+ handler.onPageFinished('https://youtube.com');
});
testWidgets('onPageFinished changed', (WidgetTester tester) async {
@@ -754,12 +674,13 @@
},
));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final WebViewPlatformCallbacksHandler handler = captureBuildArgs(
+ mockWebViewPlatform,
+ webViewPlatformCallbacksHandler: true,
+ ).last;
+ handler.onPageFinished('https://youtube.com');
- platformWebView.fakeOnPageFinishedCallback();
-
- expect(platformWebView.currentUrl, returnedUrl);
+ expect(returnedUrl, 'https://youtube.com');
});
});
@@ -774,10 +695,11 @@
},
));
- final FakePlatformWebView? platformWebView =
- fakePlatformViewsController.lastCreatedView;
-
- platformWebView?.fakeOnProgressCallback(50);
+ final WebViewPlatformCallbacksHandler handler = captureBuildArgs(
+ mockWebViewPlatform,
+ webViewPlatformCallbacksHandler: true,
+ ).single;
+ handler.onProgress(50);
expect(loadingProgress, 50);
});
@@ -788,11 +710,13 @@
onProgress: null,
));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final WebViewPlatformCallbacksHandler handler = captureBuildArgs(
+ mockWebViewPlatform,
+ webViewPlatformCallbacksHandler: true,
+ ).single;
// This is to test that it does not crash on a null callback.
- platformWebView.fakeOnProgressCallback(50);
+ handler.onProgress(50);
});
testWidgets('onLoadingProgress changed', (WidgetTester tester) async {
@@ -810,10 +734,11 @@
},
));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
-
- platformWebView.fakeOnProgressCallback(50);
+ final WebViewPlatformCallbacksHandler handler = captureBuildArgs(
+ mockWebViewPlatform,
+ webViewPlatformCallbacksHandler: true,
+ ).last;
+ handler.onProgress(50);
expect(loadingProgress, 50);
});
@@ -825,10 +750,12 @@
initialUrl: 'https://youtube.com',
));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final CreationParams params = captureBuildArgs(
+ mockWebViewPlatform,
+ creationParams: true,
+ ).single;
- expect(platformWebView.hasNavigationDelegate, false);
+ expect(params.webSettings!.hasNavigationDelegate, false);
await tester.pumpWidget(WebView(
initialUrl: 'https://youtube.com',
@@ -836,7 +763,12 @@
NavigationDecision.navigate,
));
- expect(platformWebView.hasNavigationDelegate, true);
+ final WebSettings updateSettings =
+ verify(mockWebViewPlatformController.updateSettings(captureAny))
+ .captured
+ .single;
+
+ expect(updateSettings.hasNavigationDelegate, true);
});
testWidgets('Block navigation', (WidgetTester tester) async {
@@ -852,22 +784,38 @@
: NavigationDecision.prevent;
}));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final List<dynamic> args = captureBuildArgs(
+ mockWebViewPlatform,
+ creationParams: true,
+ webViewPlatformCallbacksHandler: true,
+ );
- expect(platformWebView.hasNavigationDelegate, true);
+ final CreationParams params = args[0];
+ expect(params.webSettings!.hasNavigationDelegate, true);
- platformWebView.fakeNavigate('https://www.google.com');
+ final WebViewPlatformCallbacksHandler handler = args[1];
+
// 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(
+ handler.onNavigationRequest(
+ url: 'https://www.google.com',
+ isForMainFrame: true,
+ ),
+ completion(false),
+ );
+
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');
+ expect(
+ handler.onNavigationRequest(
+ url: 'https://flutter.dev',
+ isForMainFrame: true,
+ ),
+ completion(true),
+ );
});
});
@@ -877,41 +825,50 @@
debuggingEnabled: true,
));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final CreationParams params = captureBuildArgs(
+ mockWebViewPlatform,
+ creationParams: true,
+ ).single;
- expect(platformWebView.debuggingEnabled, true);
+ expect(params.webSettings!.debuggingEnabled, true);
});
testWidgets('defaults to false', (WidgetTester tester) async {
await tester.pumpWidget(const WebView());
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final CreationParams params = captureBuildArgs(
+ mockWebViewPlatform,
+ creationParams: true,
+ ).single;
- expect(platformWebView.debuggingEnabled, false);
+ expect(params.webSettings!.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);
+ final WebSettings enabledSettings =
+ verify(mockWebViewPlatformController.updateSettings(captureAny))
+ .captured
+ .last;
+ expect(enabledSettings.debuggingEnabled, true);
await tester.pumpWidget(WebView(
key: key,
debuggingEnabled: false,
));
- expect(platformWebView.debuggingEnabled, false);
+ final WebSettings disabledSettings =
+ verify(mockWebViewPlatformController.updateSettings(captureAny))
+ .captured
+ .last;
+ expect(disabledSettings.debuggingEnabled, false);
});
});
@@ -921,46 +878,56 @@
zoomEnabled: true,
));
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final CreationParams params = captureBuildArgs(
+ mockWebViewPlatform,
+ creationParams: true,
+ ).single;
- expect(platformWebView.zoomEnabled, isTrue);
+ expect(params.webSettings!.zoomEnabled, isTrue);
});
testWidgets('defaults to true', (WidgetTester tester) async {
await tester.pumpWidget(const WebView());
- final FakePlatformWebView platformWebView =
- fakePlatformViewsController.lastCreatedView!;
+ final CreationParams params = captureBuildArgs(
+ mockWebViewPlatform,
+ creationParams: true,
+ ).single;
- expect(platformWebView.zoomEnabled, isTrue);
+ expect(params.webSettings!.zoomEnabled, isTrue);
});
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,
zoomEnabled: true,
));
- expect(platformWebView.zoomEnabled, isTrue);
+ final WebSettings enabledSettings =
+ verify(mockWebViewPlatformController.updateSettings(captureAny))
+ .captured
+ .last;
+ // Zoom defaults to true, so no changes are made to settings.
+ expect(enabledSettings.zoomEnabled, isNull);
await tester.pumpWidget(WebView(
key: key,
zoomEnabled: false,
));
- expect(platformWebView.zoomEnabled, isFalse);
+ final WebSettings disabledSettings =
+ verify(mockWebViewPlatformController.updateSettings(captureAny))
+ .captured
+ .last;
+ expect(disabledSettings.zoomEnabled, isFalse);
});
});
group('Custom platform implementation', () {
- setUpAll(() {
+ setUp(() {
WebView.platform = MyWebViewPlatform();
});
tearDownAll(() {
@@ -1017,16 +984,19 @@
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!;
+ final CreationParams params = captureBuildArgs(
+ mockWebViewPlatform,
+ creationParams: true,
+ ).single;
- expect(platformWebView.userAgent, isNull);
+ expect(params.webSettings!.userAgent.value, isNull);
await tester.pumpWidget(const WebView(
initialUrl: 'https://youtube.com',
@@ -1034,264 +1004,74 @@
userAgent: 'UA',
));
- expect(platformWebView.userAgent, 'UA');
+ final WebSettings settings =
+ verify(mockWebViewPlatformController.updateSettings(captureAny))
+ .captured
+ .last;
+ expect(settings.userAgent.value, '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'];
- zoomEnabled = params['settings']['zoomEnabled'] ?? true;
- channel = MethodChannel(
- 'plugins.flutter.io/webview_$id', const StandardMethodCodec());
- channel.setMockMethodCallHandler(onMethodCall);
- }
-
- late 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;
- bool? zoomEnabled;
-
- String? lastRunJavaScriptString;
-
- 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'];
- if (call.arguments['zoomEnabled'] != null) {
- zoomEnabled = call.arguments['zoomEnabled'];
- }
- break;
- case 'canGoBack':
- return Future<bool>.sync(() => currentPosition > 0);
- case 'canGoForward':
- return Future<bool>.sync(() => currentPosition < history.length - 1);
- case 'goBack':
- currentPosition = max(-1, currentPosition - 1);
- return Future<void>.sync(() {});
- case 'goForward':
- currentPosition = min(history.length - 1, currentPosition + 1);
- return Future<void>.sync(() {});
- case 'reload':
- amountOfReloadsOnCurrentUrl++;
- return Future<void>.sync(() {});
- case 'currentUrl':
- return Future<String?>.value(currentUrl);
- case 'runJavascriptReturningResult':
- case 'evaluateJavascript':
- lastRunJavaScriptString = call.arguments;
- return Future<dynamic>.value(call.arguments);
- case 'runJavascript':
- lastRunJavaScriptString = call.arguments;
- return Future<void>.sync(() {});
- 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));
- _ambiguate(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));
- _ambiguate(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},
- ));
-
- _ambiguate(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},
- ));
-
- _ambiguate(ServicesBinding.instance)!
- .defaultBinaryMessenger
- .handlePlatformMessage(
- channel.name,
- data,
- (ByteData? data) {},
- );
- }
-
- void fakeOnProgressCallback(int progress) {
- final StandardMethodCodec codec = const StandardMethodCodec();
-
- final ByteData data = codec.encodeMethodCall(MethodCall(
- 'onProgress',
- <dynamic, dynamic>{'progress': progress},
- ));
-
- _ambiguate(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;
- }
+List<dynamic> captureBuildArgs(
+ MockWebViewPlatform mockWebViewPlatform, {
+ bool context = false,
+ bool creationParams = false,
+ bool webViewPlatformCallbacksHandler = false,
+ bool javascriptChannelRegistry = false,
+ bool onWebViewPlatformCreated = false,
+ bool gestureRecognizers = false,
+}) {
+ return verify(mockWebViewPlatform.build(
+ context: context ? captureAnyNamed('context') : anyNamed('context'),
+ creationParams: creationParams
+ ? captureAnyNamed('creationParams')
+ : anyNamed('creationParams'),
+ webViewPlatformCallbacksHandler: webViewPlatformCallbacksHandler
+ ? captureAnyNamed('webViewPlatformCallbacksHandler')
+ : anyNamed('webViewPlatformCallbacksHandler'),
+ javascriptChannelRegistry: javascriptChannelRegistry
+ ? captureAnyNamed('javascriptChannelRegistry')
+ : anyNamed('javascriptChannelRegistry'),
+ onWebViewPlatformCreated: onWebViewPlatformCreated
+ ? captureAnyNamed('onWebViewPlatformCreated')
+ : anyNamed('onWebViewPlatformCreated'),
+ gestureRecognizers: gestureRecognizers
+ ? captureAnyNamed('gestureRecognizers')
+ : anyNamed('gestureRecognizers'),
+ )).captured;
}
-class _FakePlatformViewsController {
- FakePlatformWebView? lastCreatedView;
+// This Widget ensures that onWebViewPlatformCreated is only called once when
+// making multiple calls to `WidgetTester.pumpWidget` with different parameters
+// for the WebView.
+class TestPlatformWebView extends StatefulWidget {
+ const TestPlatformWebView({
+ Key? key,
+ required this.mockWebViewPlatformController,
+ this.onWebViewPlatformCreated,
+ }) : super(key: key);
- 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(() {});
+ final MockWebViewPlatformController mockWebViewPlatformController;
+ final WebViewPlatformCreatedCallback? onWebViewPlatformCreated;
+
+ @override
+ State<StatefulWidget> createState() => TestPlatformWebViewState();
+}
+
+class TestPlatformWebViewState extends State<TestPlatformWebView> {
+ @override
+ void initState() {
+ super.initState();
+ WebViewPlatformCreatedCallback? onWebViewPlatformCreated =
+ widget.onWebViewPlatformCreated;
+ if (onWebViewPlatformCreated != null) {
+ onWebViewPlatformCreated(widget.mockWebViewPlatformController);
}
}
- 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;
- });
- }
- return Future<bool>.sync(() => true);
- }
-
- void reset() {
- hasCookies = true;
+ @override
+ Widget build(BuildContext context) {
+ return Container();
}
}
@@ -1381,10 +1161,3 @@
.matches(creationParams.javascriptChannelNames, matchState);
}
}
-
-/// This allows a value of type T or T? to be treated as a value of type T?.
-///
-/// We use this so that APIs that have become non-nullable can still be used
-/// with `!` and `?` on the stable branch.
-// TODO(ianh): Remove this once we roll stable in late 2021.
-T? _ambiguate<T>(T? value) => value;
diff --git a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.mocks.dart b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.mocks.dart
new file mode 100644
index 0000000..b9d43cc
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.mocks.dart
@@ -0,0 +1,178 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Mocks generated by Mockito 5.0.16 from annotations
+// in webview_flutter/test/webview_flutter_test.dart.
+// Do not manually edit this file.
+
+import 'dart:async' as _i9;
+
+import 'package:flutter/foundation.dart' as _i7;
+import 'package:flutter/gestures.dart' as _i8;
+import 'package:flutter/widgets.dart' as _i2;
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_platform_interface/src/platform_interface/javascript_channel_registry.dart'
+ as _i6;
+import 'package:webview_flutter_platform_interface/src/platform_interface/webview_platform.dart'
+ as _i3;
+import 'package:webview_flutter_platform_interface/src/platform_interface/webview_platform_callbacks_handler.dart'
+ as _i5;
+import 'package:webview_flutter_platform_interface/src/platform_interface/webview_platform_controller.dart'
+ as _i10;
+import 'package:webview_flutter_platform_interface/src/types/types.dart' as _i4;
+
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+
+class _FakeWidget_0 extends _i1.Fake implements _i2.Widget {
+ @override
+ String toString({_i2.DiagnosticLevel? minLevel = _i2.DiagnosticLevel.info}) =>
+ super.toString();
+}
+
+/// A class which mocks [WebViewPlatform].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebViewPlatform extends _i1.Mock implements _i3.WebViewPlatform {
+ MockWebViewPlatform() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i2.Widget build(
+ {_i2.BuildContext? context,
+ _i4.CreationParams? creationParams,
+ _i5.WebViewPlatformCallbacksHandler? webViewPlatformCallbacksHandler,
+ _i6.JavascriptChannelRegistry? javascriptChannelRegistry,
+ _i3.WebViewPlatformCreatedCallback? onWebViewPlatformCreated,
+ Set<_i7.Factory<_i8.OneSequenceGestureRecognizer>>?
+ gestureRecognizers}) =>
+ (super.noSuchMethod(
+ Invocation.method(#build, [], {
+ #context: context,
+ #creationParams: creationParams,
+ #webViewPlatformCallbacksHandler: webViewPlatformCallbacksHandler,
+ #javascriptChannelRegistry: javascriptChannelRegistry,
+ #onWebViewPlatformCreated: onWebViewPlatformCreated,
+ #gestureRecognizers: gestureRecognizers
+ }),
+ returnValue: _FakeWidget_0()) as _i2.Widget);
+ @override
+ _i9.Future<bool> clearCookies() =>
+ (super.noSuchMethod(Invocation.method(#clearCookies, []),
+ returnValue: Future<bool>.value(false)) as _i9.Future<bool>);
+ @override
+ String toString() => super.toString();
+}
+
+/// A class which mocks [WebViewPlatformController].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebViewPlatformController extends _i1.Mock
+ implements _i10.WebViewPlatformController {
+ MockWebViewPlatformController() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i9.Future<void> loadUrl(String? url, Map<String, String>? headers) =>
+ (super.noSuchMethod(Invocation.method(#loadUrl, [url, headers]),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
+ _i9.Future<void> updateSettings(_i4.WebSettings? setting) =>
+ (super.noSuchMethod(Invocation.method(#updateSettings, [setting]),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
+ _i9.Future<String?> currentUrl() =>
+ (super.noSuchMethod(Invocation.method(#currentUrl, []),
+ returnValue: Future<String?>.value()) as _i9.Future<String?>);
+ @override
+ _i9.Future<bool> canGoBack() =>
+ (super.noSuchMethod(Invocation.method(#canGoBack, []),
+ returnValue: Future<bool>.value(false)) as _i9.Future<bool>);
+ @override
+ _i9.Future<bool> canGoForward() =>
+ (super.noSuchMethod(Invocation.method(#canGoForward, []),
+ returnValue: Future<bool>.value(false)) as _i9.Future<bool>);
+ @override
+ _i9.Future<void> goBack() =>
+ (super.noSuchMethod(Invocation.method(#goBack, []),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
+ _i9.Future<void> goForward() =>
+ (super.noSuchMethod(Invocation.method(#goForward, []),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
+ _i9.Future<void> reload() =>
+ (super.noSuchMethod(Invocation.method(#reload, []),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
+ _i9.Future<void> clearCache() =>
+ (super.noSuchMethod(Invocation.method(#clearCache, []),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
+ _i9.Future<String> evaluateJavascript(String? javascript) =>
+ (super.noSuchMethod(Invocation.method(#evaluateJavascript, [javascript]),
+ returnValue: Future<String>.value('')) as _i9.Future<String>);
+ @override
+ _i9.Future<void> runJavascript(String? javascript) =>
+ (super.noSuchMethod(Invocation.method(#runJavascript, [javascript]),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
+ _i9.Future<String> runJavascriptReturningResult(String? javascript) =>
+ (super.noSuchMethod(
+ Invocation.method(#runJavascriptReturningResult, [javascript]),
+ returnValue: Future<String>.value('')) as _i9.Future<String>);
+ @override
+ _i9.Future<void> addJavascriptChannels(Set<String>? javascriptChannelNames) =>
+ (super.noSuchMethod(
+ Invocation.method(#addJavascriptChannels, [javascriptChannelNames]),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
+ _i9.Future<void> removeJavascriptChannels(
+ Set<String>? javascriptChannelNames) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #removeJavascriptChannels, [javascriptChannelNames]),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
+ _i9.Future<String?> getTitle() =>
+ (super.noSuchMethod(Invocation.method(#getTitle, []),
+ returnValue: Future<String?>.value()) as _i9.Future<String?>);
+ @override
+ _i9.Future<void> scrollTo(int? x, int? y) =>
+ (super.noSuchMethod(Invocation.method(#scrollTo, [x, y]),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
+ _i9.Future<void> scrollBy(int? x, int? y) =>
+ (super.noSuchMethod(Invocation.method(#scrollBy, [x, y]),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
+ _i9.Future<int> getScrollX() =>
+ (super.noSuchMethod(Invocation.method(#getScrollX, []),
+ returnValue: Future<int>.value(0)) as _i9.Future<int>);
+ @override
+ _i9.Future<int> getScrollY() =>
+ (super.noSuchMethod(Invocation.method(#getScrollY, []),
+ returnValue: Future<int>.value(0)) as _i9.Future<int>);
+ @override
+ String toString() => super.toString();
+}