How to test flutter url_launcher that email app opens?
Asked Answered
R

4

9

I do have a Snackbar with a SnackbarAction which should open the default email app with a default subject and body on tap. I am wondering if there is somehow the possibility to verify if this really happens with some unit tests.

My Snackbar code looks like this:

SnackBar get snackbar =>
      SnackBar(
          content: Text(message),
          action: SnackBarAction(
              key: const Key('ErrorSnackbarAction'),
              label: AppLocalizations
                  .of(_context)
                  .report,
              onPressed: () async => await launch('mailto:[email protected]?subject=TestSubject&body=TestBody')));

I am already verifying the appearance which works fine:

group('ErrorSnackbar', () {
  testWidgets('appearance test', (WidgetTester tester) async {
    await tester.pumpWidget(_generateSnackbarApp());

    await _showSnackbar(tester);

    expect(find.text(userMessage), findsOneWidget);
    expect(find.byWidgetPredicate((Widget widget) =>
    widget is SnackBarAction && widget.label == 'Report'), findsOneWidget);
  });

  testWidgets('error report test', (WidgetTester tester) async {
    await tester.pumpWidget(_generateSnackbarApp());

    await _showSnackbar(tester);

    tester.tap(find.byKey(errorSnackbarAction));
    await tester.pump();

   // how to verify that the default email app was opened
  // with expected subject and body?

  });
});
Roxyroy answered 25/2, 2019 at 15:8 Comment(0)
A
9

Short answer: You can't.

The launch with mailto is handled by the OS of the device and is out of context of the flutter app. As the flutter test package focuses on the flutter app, what happens on the OS is out of reach.

Aixlachapelle answered 23/4, 2019 at 10:44 Comment(0)
A
3

You can ensure that launchUrl is called and the expected parameters were passed. The url_launcher package should be tested. Therefore, we can expect that the email app opens, when we call launchUrl with the mailto: schema.

Here is a short introduction on how to test the url_launcher package:

Add plugin_platform_interface and url_launcher_platform_interface to your dev dependencies:

dev_dependencies:
  flutter_test:
    sdk: flutter
  plugin_platform_interface: any
  url_launcher_platform_interface: any

Copy the mock_url_launcher_platform.dart from the url_launcher package: https://github.com/flutter/plugins/blob/main/packages/url_launcher/url_launcher/test/mocks/mock_url_launcher_platform.dart

Now you can test the launchUrl calls like this:

void main() {
  late MockUrlLauncher mock;

  setUp(() {
    mock = MockUrlLauncher();
    UrlLauncherPlatform.instance = mock;
  });

  group('$Link', () {
    testWidgets('calls url_launcher for external URLs with blank target',
        (WidgetTester tester) async {
      FollowLink? followLink;

      await tester.pumpWidget(Link(
        uri: Uri.parse('http://example.com/foobar'),
        target: LinkTarget.blank,
        builder: (BuildContext context, FollowLink? followLink2) {
          followLink = followLink2;
          return Container();
        },
      ));

      mock
        ..setLaunchExpectations(
          url: 'http://example.com/foobar',
          useSafariVC: false,
          useWebView: false,
          universalLinksOnly: false,
          enableJavaScript: true,
          enableDomStorage: true,
          headers: <String, String>{},
          webOnlyWindowName: null,
        )
        ..setResponse(true);
      await followLink!();
      expect(mock.canLaunchCalled, isTrue);
      expect(mock.launchCalled, isTrue);
    });
  });
}

Copied the test from https://github.com/flutter/plugins/blob/main/packages/url_launcher/url_launcher/test/link_test.dart

Antaeus answered 6/6, 2022 at 21:48 Comment(0)
S
2

Unit test wise

I think the best way to test it is to wrap url launcher with your own class. This way you can mock it and check that your logic calls your wrapper class function to launch the mail app. This should be enough.

As for the actual mail app or browser (in my case) you should trust the library todo what it supposed to so no need to unit test it really.

Surveyor answered 4/7, 2022 at 7:19 Comment(0)
T
0

Below is the solution to mock url launch.

Code to test

Future<void> openWallet() async {
    unawaited(launchUrl(Uri.parse('wallet://')));
  }

Steps to mock and write up test.

Add below dependencies in pubspec.yaml

dev_dependencies:
  url_launcher_platform_interface: ^2.3.2
  very_good_analysis: ^5.1.0

Now create mock

class MockUrlLauncher extends Mock with MockPlatformInterfaceMixin implements UrlLauncherPlatform {}

Now setup mock

MockUrlLauncher _setupMockUrlLauncher() {
  final mock = MockUrlLauncher();
  registerFallbackValue(const LaunchOptions());

  when(() => mock.launchUrl(any(), any())).thenAnswer((_) async => true);
  return mock;
}

And now create mock instance

final mockLauncher = _setupMockUrlLauncher();

Set the mock launcher instance as default platform instance

UrlLauncherPlatform.instance = mockLauncher;

And now time to add a unit test.

test('open wallet', () async {
    await ejIosWallet.openWallet();
    verify(() => mockLauncher.launchUrl('wallet://', any())).called(1);
  });

This test fails as expected if we change the launch url in the test.

Note:

Flutter Version "3.22.0"
Thornburg answered 8/7 at 11:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.