diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 300d6d9342f5..1a07090992d5 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.2.7 + +* Minor unit test changes and added a lint for public DartDocs. + ## 5.2.6 * Remove AndroidX warnings. diff --git a/packages/url_launcher/url_launcher/analysis_options.yaml b/packages/url_launcher/url_launcher/analysis_options.yaml new file mode 100644 index 000000000000..6c7fd57bb022 --- /dev/null +++ b/packages/url_launcher/url_launcher/analysis_options.yaml @@ -0,0 +1,11 @@ +# This exists to add a lint for missing API docs just on this specific package, +# since not all packages have coverage for all their public members yet and +# adding it in would be non-trivial. `public_member_api_docs` should be applied +# to new packages going forward, and ideally the main `analysis_options.yaml` +# file as soon as possible. + +include: ../../../analysis_options.yaml + +linter: + rules: + - public_member_api_docs diff --git a/packages/url_launcher/url_launcher/example/lib/main.dart b/packages/url_launcher/url_launcher/example/lib/main.dart index b4a7e4275bfc..00ab6c5b047d 100644 --- a/packages/url_launcher/url_launcher/example/lib/main.dart +++ b/packages/url_launcher/url_launcher/example/lib/main.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// ignore_for_file: public_member_api_docs + import 'dart:async'; import 'package:flutter/material.dart'; diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 2477e118586e..e0c59134f8f2 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 5.2.6 +version: 5.2.7 flutter: plugin: diff --git a/packages/url_launcher/url_launcher/test/url_launcher_test.dart b/packages/url_launcher/url_launcher/test/url_launcher_test.dart index e7150bebde05..2481e5a0ee63 100644 --- a/packages/url_launcher/url_launcher/test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher/test/url_launcher_test.dart @@ -2,8 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; +import 'dart:ui'; +import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; -import 'package:test/test.dart'; +import 'package:flutter/foundation.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; import 'package:flutter/services.dart' show PlatformException; @@ -11,166 +14,197 @@ import 'package:flutter/services.dart' show PlatformException; void main() { final MockUrlLauncher mock = MockUrlLauncher(); when(mock.isMock).thenReturn(true); - UrlLauncherPlatform.instance = mock; - test('canLaunch', () async { - await canLaunch('http://example.com/'); - expect(verify(mock.canLaunch(captureAny)).captured.single, - 'http://example.com/'); + test('closeWebView default behavior', () async { + await closeWebView(); + verify(mock.closeWebView()); }); - test('launch default behavior', () async { - await launch('http://example.com/'); - expect( - verify(mock.launch( - captureAny, - useSafariVC: captureAnyNamed('useSafariVC'), - useWebView: captureAnyNamed('useWebView'), - enableJavaScript: captureAnyNamed('enableJavaScript'), - enableDomStorage: captureAnyNamed('enableDomStorage'), - universalLinksOnly: captureAnyNamed('universalLinksOnly'), - headers: captureAnyNamed('headers'), - )).captured, - [ - 'http://example.com/', - true, - false, - false, - false, - false, - {}, - ], - ); - }); + group('canLaunch', () { + test('returns true', () async { + when(mock.canLaunch('foo')).thenAnswer((_) => Future.value(true)); - test('launch with headers', () async { - await launch( - 'http://example.com/', - headers: {'key': 'value'}, - ); - expect( - verify(mock.launch( - any, - useSafariVC: anyNamed('useSafariVC'), - useWebView: anyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: captureAnyNamed('headers'), - )).captured.single, - {'key': 'value'}, - ); - }); + final bool result = await canLaunch('foo'); - test('launch force SafariVC', () async { - await launch('http://example.com/', forceSafariVC: true); - expect( - verify(mock.launch( - any, - useSafariVC: captureAnyNamed('useSafariVC'), - useWebView: anyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )).captured.single, - true, - ); - }); + expect(result, isTrue); + }); - test('launch universal links only', () async { - await launch('http://example.com/', - forceSafariVC: false, universalLinksOnly: true); - expect( - verify(mock.launch( - any, - useSafariVC: captureAnyNamed('useSafariVC'), - useWebView: anyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: captureAnyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )).captured, - [false, true], - ); - }); + test('returns false', () async { + when(mock.canLaunch('foo')).thenAnswer((_) => Future.value(false)); - test('launch force WebView', () async { - await launch('http://example.com/', forceWebView: true); - expect( - verify(mock.launch( - any, - useSafariVC: anyNamed('useSafariVC'), - useWebView: captureAnyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )).captured.single, - true, - ); - }); + final bool result = await canLaunch('foo'); - test('launch force WebView enable javascript', () async { - await launch('http://example.com/', - forceWebView: true, enableJavaScript: true); - expect( - verify(mock.launch( - any, - useSafariVC: anyNamed('useSafariVC'), - useWebView: captureAnyNamed('useWebView'), - enableJavaScript: captureAnyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )).captured, - [true, true], - ); + expect(result, isFalse); + }); }); + group('launch', () { + test('requires a non-null urlString', () { + expect(() => launch(null), throwsAssertionError); + }); - test('launch force WebView enable DOM storage', () async { - await launch('http://example.com/', - forceWebView: true, enableDomStorage: true); - expect( - verify(mock.launch( - any, - useSafariVC: anyNamed('useSafariVC'), - useWebView: captureAnyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: captureAnyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )).captured, - [true, true], - ); - }); + test('default behavior', () async { + await launch('http://flutter.dev/'); + expect( + verify(mock.launch( + captureAny, + useSafariVC: captureAnyNamed('useSafariVC'), + useWebView: captureAnyNamed('useWebView'), + enableJavaScript: captureAnyNamed('enableJavaScript'), + enableDomStorage: captureAnyNamed('enableDomStorage'), + universalLinksOnly: captureAnyNamed('universalLinksOnly'), + headers: captureAnyNamed('headers'), + )).captured, + [ + 'http://flutter.dev/', + true, + false, + false, + false, + false, + {}, + ], + ); + }); - test('launch force SafariVC to false', () async { - await launch('http://example.com/', forceSafariVC: false); - expect( - // ignore: missing_required_param - verify(mock.launch( - any, - useSafariVC: captureAnyNamed('useSafariVC'), - useWebView: anyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )).captured.single, - false, - ); - }); + test('with headers', () async { + await launch( + 'http://flutter.dev/', + headers: {'key': 'value'}, + ); + expect( + verify(mock.launch( + any, + useSafariVC: anyNamed('useSafariVC'), + useWebView: anyNamed('useWebView'), + enableJavaScript: anyNamed('enableJavaScript'), + enableDomStorage: anyNamed('enableDomStorage'), + universalLinksOnly: anyNamed('universalLinksOnly'), + headers: captureAnyNamed('headers'), + )).captured.single, + {'key': 'value'}, + ); + }); - test('cannot launch a non-web in webview', () async { - expect(() async => await launch('tel:555-555-5555', forceWebView: true), - throwsA(isA())); - }); + test('force SafariVC', () async { + await launch('http://flutter.dev/', forceSafariVC: true); + expect( + verify(mock.launch( + any, + useSafariVC: captureAnyNamed('useSafariVC'), + useWebView: anyNamed('useWebView'), + enableJavaScript: anyNamed('enableJavaScript'), + enableDomStorage: anyNamed('enableDomStorage'), + universalLinksOnly: anyNamed('universalLinksOnly'), + headers: anyNamed('headers'), + )).captured.single, + true, + ); + }); - test('closeWebView default behavior', () async { - await closeWebView(); - verify(mock.closeWebView()); + test('universal links only', () async { + await launch('http://flutter.dev/', + forceSafariVC: false, universalLinksOnly: true); + expect( + verify(mock.launch( + any, + useSafariVC: captureAnyNamed('useSafariVC'), + useWebView: anyNamed('useWebView'), + enableJavaScript: anyNamed('enableJavaScript'), + enableDomStorage: anyNamed('enableDomStorage'), + universalLinksOnly: captureAnyNamed('universalLinksOnly'), + headers: anyNamed('headers'), + )).captured, + [false, true], + ); + }); + + test('force WebView', () async { + await launch('http://flutter.dev/', forceWebView: true); + expect( + verify(mock.launch( + any, + useSafariVC: anyNamed('useSafariVC'), + useWebView: captureAnyNamed('useWebView'), + enableJavaScript: anyNamed('enableJavaScript'), + enableDomStorage: anyNamed('enableDomStorage'), + universalLinksOnly: anyNamed('universalLinksOnly'), + headers: anyNamed('headers'), + )).captured.single, + true, + ); + }); + + test('force WebView enable javascript', () async { + await launch('http://flutter.dev/', + forceWebView: true, enableJavaScript: true); + expect( + verify(mock.launch( + any, + useSafariVC: anyNamed('useSafariVC'), + useWebView: captureAnyNamed('useWebView'), + enableJavaScript: captureAnyNamed('enableJavaScript'), + enableDomStorage: anyNamed('enableDomStorage'), + universalLinksOnly: anyNamed('universalLinksOnly'), + headers: anyNamed('headers'), + )).captured, + [true, true], + ); + }); + + test('force WebView enable DOM storage', () async { + await launch('http://flutter.dev/', + forceWebView: true, enableDomStorage: true); + expect( + verify(mock.launch( + any, + useSafariVC: anyNamed('useSafariVC'), + useWebView: captureAnyNamed('useWebView'), + enableJavaScript: anyNamed('enableJavaScript'), + enableDomStorage: captureAnyNamed('enableDomStorage'), + universalLinksOnly: anyNamed('universalLinksOnly'), + headers: anyNamed('headers'), + )).captured, + [true, true], + ); + }); + + test('force SafariVC to false', () async { + await launch('http://flutter.dev/', forceSafariVC: false); + expect( + // ignore: missing_required_param + verify(mock.launch( + any, + useSafariVC: captureAnyNamed('useSafariVC'), + useWebView: anyNamed('useWebView'), + enableJavaScript: anyNamed('enableJavaScript'), + enableDomStorage: anyNamed('enableDomStorage'), + universalLinksOnly: anyNamed('universalLinksOnly'), + headers: anyNamed('headers'), + )).captured.single, + false, + ); + }); + + test('cannot launch a non-web in webview', () async { + expect(() async => await launch('tel:555-555-5555', forceWebView: true), + throwsA(isA())); + }); + + test('controls system UI when changing statusBarBrightness', () async { + final TestWidgetsFlutterBinding binding = + TestWidgetsFlutterBinding.ensureInitialized(); + debugDefaultTargetPlatformOverride = TargetPlatform.iOS; + binding.renderView.automaticSystemUiAdjustment = true; + final Future launchResult = + launch('http://flutter.dev/', statusBarBrightness: Brightness.dark); + + // Should take over control of the automaticSystemUiAdjustment while it's + // pending, then restore it back to normal after the launch finishes. + expect(binding.renderView.automaticSystemUiAdjustment, isFalse); + await launchResult; + expect(binding.renderView.automaticSystemUiAdjustment, isTrue); + }); }); } diff --git a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md index 7aa8ee011524..18d373d183f2 100644 --- a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.3 + +* Minor DartDoc changes and add a lint for missing DartDocs. + ## 1.0.2 * Use package URI in test directory to import code from lib. diff --git a/packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml b/packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml new file mode 100644 index 000000000000..6c7fd57bb022 --- /dev/null +++ b/packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml @@ -0,0 +1,11 @@ +# This exists to add a lint for missing API docs just on this specific package, +# since not all packages have coverage for all their public members yet and +# adding it in would be non-trivial. `public_member_api_docs` should be applied +# to new packages going forward, and ideally the main `analysis_options.yaml` +# file as soon as possible. + +include: ../../../analysis_options.yaml + +linter: + rules: + - public_member_api_docs diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart b/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart index a17aa0626126..64eeec7cae2d 100644 --- a/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart +++ b/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart @@ -24,17 +24,15 @@ abstract class UrlLauncherPlatform { @visibleForTesting bool get isMock => false; + static UrlLauncherPlatform _instance = MethodChannelUrlLauncher(); + /// The default instance of [UrlLauncherPlatform] to use. /// - /// Platform-specific plugins should override this with their own - /// platform-specific class that extends [UrlLauncherPlatform] when they - /// register themselves. - /// /// Defaults to [MethodChannelUrlLauncher]. - static UrlLauncherPlatform _instance = MethodChannelUrlLauncher(); - static UrlLauncherPlatform get instance => _instance; + /// Platform-specific plugins should set this with their own platform-specific + /// class that extends [UrlLauncherPlatform] when they register themselves. // TODO(amirh): Extract common platform interface logic. // https://github.com/flutter/flutter/issues/43368 static set instance(UrlLauncherPlatform instance) { diff --git a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml index 192fbe7e8066..3f7aa4832c41 100644 --- a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml +++ b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_platform_interface # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 1.0.2 +version: 1.0.3 dependencies: flutter: