// 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. import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:url_launcher_ios/src/messages.g.dart'; import 'package:url_launcher_ios/url_launcher_ios.dart'; import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; import 'url_launcher_ios_test.mocks.dart'; // A web URL to use in tests where the specifics of the URL don't matter. const String _webUrl = 'https://example.com/'; @GenerateMocks([UrlLauncherApi]) void main() { late MockUrlLauncherApi api; setUp(() { api = MockUrlLauncherApi(); }); test('registers instance', () { UrlLauncherIOS.registerWith(); expect(UrlLauncherPlatform.instance, isA()); }); group('canLaunch', () { test('handles success', () async { when(api.canLaunchUrl(_webUrl)) .thenAnswer((_) async => LaunchResult.success); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect(await launcher.canLaunch(_webUrl), true); }); test('handles failure', () async { when(api.canLaunchUrl(_webUrl)) .thenAnswer((_) async => LaunchResult.failure); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect(await launcher.canLaunch(_webUrl), false); }); test('throws PlatformException for invalid URL', () async { when(api.canLaunchUrl(_webUrl)) .thenAnswer((_) async => LaunchResult.invalidUrl); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); await expectLater( launcher.canLaunch(_webUrl), throwsA(isA().having( (PlatformException e) => e.code, 'code', 'argument_error'))); }); }); group('legacy launch', () { test('handles success', () async { when(api.launchUrl(_webUrl, any)) .thenAnswer((_) async => LaunchResult.success); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect( await launcher.launch( _webUrl, useSafariVC: false, useWebView: false, enableJavaScript: false, enableDomStorage: false, universalLinksOnly: false, headers: const {}, ), true); verifyNever(api.openUrlInSafariViewController(any)); }); test('handles failure', () async { when(api.launchUrl(_webUrl, any)) .thenAnswer((_) async => LaunchResult.failure); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect( await launcher.launch( _webUrl, useSafariVC: false, useWebView: false, enableJavaScript: false, enableDomStorage: false, universalLinksOnly: false, headers: const {}, ), false); verifyNever(api.openUrlInSafariViewController(any)); }); test('throws PlatformException for invalid URL', () async { when(api.launchUrl(_webUrl, any)) .thenAnswer((_) async => LaunchResult.invalidUrl); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); await expectLater( launcher.launch( _webUrl, useSafariVC: false, useWebView: false, enableJavaScript: false, enableDomStorage: false, universalLinksOnly: false, headers: const {}, ), throwsA(isA().having( (PlatformException e) => e.code, 'code', 'argument_error'))); }); test('force SafariVC is handled', () async { when(api.openUrlInSafariViewController(_webUrl)) .thenAnswer((_) async => InAppLoadResult.success); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect( await launcher.launch( _webUrl, useSafariVC: true, useWebView: false, enableJavaScript: false, enableDomStorage: false, universalLinksOnly: false, headers: const {}, ), true); verifyNever(api.launchUrl(any, any)); }); test('universal links only is handled', () async { when(api.launchUrl(_webUrl, any)) .thenAnswer((_) async => LaunchResult.success); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect( await launcher.launch( _webUrl, useSafariVC: false, useWebView: false, enableJavaScript: false, enableDomStorage: false, universalLinksOnly: true, headers: const {}, ), true); verifyNever(api.openUrlInSafariViewController(any)); }); test('disallowing SafariVC is handled', () async { when(api.launchUrl(_webUrl, any)) .thenAnswer((_) async => LaunchResult.success); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect( await launcher.launch( _webUrl, useSafariVC: false, useWebView: false, enableJavaScript: false, enableDomStorage: false, universalLinksOnly: false, headers: const {}, ), true); verifyNever(api.openUrlInSafariViewController(any)); }); }); test('closeWebView calls through', () async { final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); await launcher.closeWebView(); verify(api.closeSafariViewController()).called(1); }); group('launch without webview', () { test('calls through', () async { when(api.launchUrl(_webUrl, any)) .thenAnswer((_) async => LaunchResult.success); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); final bool launched = await launcher.launchUrl( _webUrl, const LaunchOptions(mode: PreferredLaunchMode.externalApplication), ); expect(launched, true); verifyNever(api.openUrlInSafariViewController(any)); }); test('throws PlatformException for invalid URL', () async { when(api.launchUrl(_webUrl, any)) .thenAnswer((_) async => LaunchResult.invalidUrl); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); await expectLater( launcher.launchUrl( _webUrl, const LaunchOptions(mode: PreferredLaunchMode.externalApplication), ), throwsA(isA().having( (PlatformException e) => e.code, 'code', 'argument_error'))); }); }); group('launch with Safari view controller', () { test('calls through with inAppWebView', () async { when(api.openUrlInSafariViewController(_webUrl)) .thenAnswer((_) async => InAppLoadResult.success); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); final bool launched = await launcher.launchUrl( _webUrl, const LaunchOptions(mode: PreferredLaunchMode.inAppWebView)); expect(launched, true); verifyNever(api.launchUrl(any, any)); }); test('calls through with inAppBrowserView', () async { when(api.openUrlInSafariViewController(_webUrl)) .thenAnswer((_) async => InAppLoadResult.success); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); final bool launched = await launcher.launchUrl(_webUrl, const LaunchOptions(mode: PreferredLaunchMode.inAppBrowserView)); expect(launched, true); verifyNever(api.launchUrl(any, any)); }); test('throws PlatformException for invalid URL', () async { when(api.openUrlInSafariViewController(_webUrl)) .thenAnswer((_) async => InAppLoadResult.invalidUrl); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); await expectLater( launcher.launchUrl(_webUrl, const LaunchOptions(mode: PreferredLaunchMode.inAppWebView)), throwsA(isA().having( (PlatformException e) => e.code, 'code', 'argument_error'))); }); test('throws PlatformException for load failure', () async { when(api.openUrlInSafariViewController(_webUrl)) .thenAnswer((_) async => InAppLoadResult.failedToLoad); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); await expectLater( launcher.launchUrl(_webUrl, const LaunchOptions(mode: PreferredLaunchMode.inAppWebView)), throwsA(isA() .having((PlatformException e) => e.code, 'code', 'Error'))); }); }); group('launch with universal links', () { test('calls through', () async { when(api.launchUrl(_webUrl, any)) .thenAnswer((_) async => LaunchResult.success); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); final bool launched = await launcher.launchUrl( _webUrl, const LaunchOptions( mode: PreferredLaunchMode.externalNonBrowserApplication), ); expect(launched, true); verifyNever(api.openUrlInSafariViewController(any)); }); test('throws PlatformException for invalid URL', () async { when(api.launchUrl(_webUrl, any)) .thenAnswer((_) async => LaunchResult.invalidUrl); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); await expectLater( launcher.launchUrl( _webUrl, const LaunchOptions( mode: PreferredLaunchMode.externalNonBrowserApplication)), throwsA(isA().having( (PlatformException e) => e.code, 'code', 'argument_error'))); }); }); group('launch with platform default', () { test('uses Safari view controller for http', () async { const String httpUrl = 'http://example.com/'; when(api.openUrlInSafariViewController(httpUrl)) .thenAnswer((_) async => InAppLoadResult.success); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); final bool launched = await launcher.launchUrl(httpUrl, const LaunchOptions()); expect(launched, true); verifyNever(api.launchUrl(any, any)); }); test('uses Safari view controller for https', () async { const String httpsUrl = 'https://example.com/'; when(api.openUrlInSafariViewController(httpsUrl)) .thenAnswer((_) async => InAppLoadResult.success); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); final bool launched = await launcher.launchUrl(httpsUrl, const LaunchOptions()); expect(launched, true); verifyNever(api.launchUrl(any, any)); }); test('uses standard external for other schemes', () async { const String nonWebUrl = 'supportedcustomscheme://example.com/'; when(api.launchUrl(nonWebUrl, any)) .thenAnswer((_) async => LaunchResult.success); final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); final bool launched = await launcher.launchUrl(nonWebUrl, const LaunchOptions()); expect(launched, true); verifyNever(api.openUrlInSafariViewController(any)); }); }); group('supportsMode', () { test('returns true for platformDefault', () async { final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect(await launcher.supportsMode(PreferredLaunchMode.platformDefault), true); }); test('returns true for external application', () async { final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect( await launcher.supportsMode(PreferredLaunchMode.externalApplication), true); }); test('returns true for external non-browser application', () async { final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect( await launcher .supportsMode(PreferredLaunchMode.externalNonBrowserApplication), true); }); test('returns true for in app web view', () async { final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect( await launcher.supportsMode(PreferredLaunchMode.inAppWebView), true); }); test('returns true for in app browser view', () async { final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect(await launcher.supportsMode(PreferredLaunchMode.inAppBrowserView), true); }); }); group('supportsCloseForMode', () { test('returns true for in app web view', () async { final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect( await launcher.supportsCloseForMode(PreferredLaunchMode.inAppWebView), true); }); test('returns true for in app browser view', () async { final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect( await launcher .supportsCloseForMode(PreferredLaunchMode.inAppBrowserView), true); }); test('returns false for other modes', () async { final UrlLauncherIOS launcher = UrlLauncherIOS(api: api); expect( await launcher .supportsCloseForMode(PreferredLaunchMode.externalApplication), false); expect( await launcher.supportsCloseForMode( PreferredLaunchMode.externalNonBrowserApplication), false); }); }); }