Flutter driver handle minimalized application
Asked Answered
D

1

7

I am making some testing scenarios for my flutter application. One of the functionalities is "About us" section. When tapping on "About Us" user is redirected to the web page and application is minimalized. This is an issue because test scenario fails on this spot. Flutter is not able to find any components and it fails on this particular error

Unhandled exception:
DriverError: Failed to fulfill Tap due to remote error
Original error: Bad state: The client closed with pending request "ext.flutter.driver".
Original stack trace:
#0      new Client.withoutJson.<anonymous closure> (package:json_rpc_2/src/client.dart:70:24)
#1      _RootZone.run (dart:async/zone.dart:1445:54)
#2      _FutureListener.handleWhenComplete (dart:async/future_impl.dart:167:18)
#3      Future._propagateToListeners.handleWhenCompleteCallback (dart:async/future_impl.dart:666:39)
#4      Future._propagateToListeners (dart:async/future_impl.dart:722:37)
#5      Future._propagateToListeners (dart:async/future_impl.dart:621:9)
#6      Future._completeWithValue (dart:async/future_impl.dart:529:5)
#7      Future._asyncCompleteWithValue.<anonymous closure> (dart:async/future_impl.dart:567:7)
#8      _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
#9      _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
#10     _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:118:13)
#11     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:404:11)
#12     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:428:5)
#13     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)


#0      VMServiceFlutterDriver.sendCommand (package:flutter_driver/src/driver/vmservice_driver.dart:345:7)
<asynchronous suspension>
#1      FlutterDriver.tap (package:flutter_driver/src/driver/driver.dart:207:11)
#2      LoginPage.tapOnAboutUs (file:///D:/Projects/app/test_driver/page_objects/login_page.dart:52:19)
#3      aboutUs_steps.iClickOnAboutUsOnLoginPage (file:///D:/Projects/app/test_driver/steps/aboutUs_steps.dart:16:15)
<asynchronous suspension>
#4      _InstanceMirror._invoke (dart:mirrors-patch/mirrors_impl.dart:337:37)
#5      _InstanceMirror.invoke (dart:mirrors-patch/mirrors_impl.dart:333:25)
#6      OguretsState.invokeStep.<anonymous closure> (package:ogurets/src/ogurets_internal.dart:316:29)
#7      new Future.sync (dart:async/future.dart:223:31)
#8      OguretsState.invokeStep (package:ogurets/src/ogurets_internal.dart:315:25)
#9      OguretsState.executeStep (package:ogurets/src/ogurets_internal.dart:296:13)
<asynchronous suspension>
#10     OguretsState._findClassStyleStepRunners.<anonymous closure> (package:ogurets/src/ogurets_internal.dart:270:19)
#11     _Scenario._executeSubScenario (package:ogurets/src/model/scenario.dart:163:43)
<asynchronous suspension>
#12     _Scenario.execute (package:ogurets/src/model/scenario.dart:57:17)
#13     _Feature.execute (package:ogurets/src/model/feature.dart:41:64)
#14     OguretsOpts.processFeatureFile (package:ogurets/src/ogurets_opts.dart:327:49)
<asynchronous suspension>
#15     OguretsOpts.run (package:ogurets/src/ogurets_opts.dart:303:17)
<asynchronous suspension>
#16     main (file:///D:/Projects/app/test_driver/ogurets_flutter_test.dart:30:13)
#17     _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:299:32)
#18     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)

Is there any possible solution which could unminimalize the app from background?

I was trying to use default flutter hooks, but with no correct result.

These are files and methods which I use

Feature: AboutUsLink
  As a tester I test the functionality of the About Us link


  Scenario: Login - About us - Button functionality
    Given I click on About us on Login Page



class aboutUs_steps {
  FlutterOgurets _world;

  aboutUs_steps(this._world);

  @Given(r'I click on About us on Login Page')
  void iClickOnAboutUsOnLoginPage() async {
    LoginPage loginPage = new LoginPage(_world.driver);
    await Future.delayed(Duration(seconds: FUTURE_DELAY));
    loginPage.tapOnAboutUs();
  }
}

and the method in LoginPage

  Future<void> tapOnAboutUs() async {
    await _driver.tap(aboutUs);
  }
Driver answered 23/10, 2020 at 10:41 Comment(0)
B
0

This is a scenario where I would choose a widget test over an integration test (using flutter driver), as it is quicker to execute and easier to verify the correct behaviour

Q: How to write a test for a feature opening an external application (like a URL in a webbrowser).

A: When redirecting to a website or any other external URL using a method like launch() you want to test that you are passing the correct parameter to launch() - in your case that would be something like https://example.com/about

Implementation: You need to mock launch() and verify it has been called with the correct parameter, a test could look something like this, where your LoginPage can be passed a mock for the launcher:

class MockLauncher extends Mock {}

void main() {
  MockLauncher mockLauncher; 
  setUp() {
    mockLauncher = MockLauncher();
    when(mockLauncher.launch(any)).thenReturn(true);
  }
  testWidgets('click on About us', (WidgetTester tester)
  async {
    await tester.pumpWidget(LoginPage(launcher: mockLauncher.launch));
    await tester.tap(find.byKey(ValueKey('about_us_link')));
    verify(mockLauncher.launch('https://example.com/about'));
    verifyNoMoreInteractions(mockLauncher);
  });
}
import 'package:url_launcher/url_launcher.dart';

class LoginPage extends ...{
  Function urlLauncher;

  LoginPage({this.urlLauncher}) {
    urlLauncher ??= launcher // use mock if it is passed in
  }
}

The same approach could also be used for integration testing, but I would suggest to reassess your reasons for doing so, as the test strategy above should be sufficent for most redirect scenarios.

Boanerges answered 30/10, 2020 at 11:43 Comment(4)
this answer would be perfect, if there wasn't a need to use classic integration test scenario like mentioned above. Your approach is perfectly fine, but I am not able to use it like you suggested. This would not follow the actual approach of testing. Even If I wanted to combine your and mine this would not work because flutter driver would throw an error that it is not possible to get dart.io libraries and so on.Driver
the point I tried to make, is that once you leave your application, you are leaving the scope of what you should be testing (like you don't want to test libraries you include). You could stub the launch(url) method with something that opens a widget which displays the parameter as text and then you can use a regular flutter driver expect text assertion. I suggest not to test the launch method which comes from a library, but test that you are passing the correct parameters.Boanerges
oh... I think that I know where you are heading. I also tried to get the link which is an input to a launch() method. And I was able to test the correctness of the link. With that being said.. I think I can be OK with that answer.Driver
if you are ok with the answer it would be great if you could mark it as answered, so others can see that there is a solution to be found :) - if you would like to continue the conversation feel free to reach out!Boanerges

© 2022 - 2024 — McMap. All rights reserved.