14

Can someone show me how to implement overriding flutter errors during widget test so I can check for my own custom errors.

I have seen snippets online mentioning this but all of my implementations fail

void main() {

  testWidgets('throws an error when scanning unknown term types', (WidgetTester tester) async {
    await tester.pumpWidget(injectTestWidget(new ItemScanScreen()));

    await tester.enterText(find.byKey(new Key('term')), '');
    await tester.tap(find.byIcon(Icons.send));
    await tester.pump();

    expect(
      tester.takeException(),
      isInstanceOf<UnrecognizedTermException>(),
      reason: 'should have thrown an UnrecognizedTermException error but didn\'t',
    );
  });
}

the code above fails with the message below even though it looks like it in fact 'caught' my error:

The following UnrecognizedTermException was thrown running a test:
Instance of 'UnrecognizedTermException'
...

I read that you could do something like the snippet below but it did not see how/where to implement it:

final errorHandled = expectAsync0((){});

FlutterError.onError = (errorDetails) {
  // handle error
  errorHandled();
});
xpeldev
  • 1,812
  • 2
  • 12
  • 23

2 Answers2

14

I use the code below in production to log errors to a server.

main.dart:

import 'dart:async';
import 'package:flutter/material.dart';
import 'logging.dart';

void main() async {
  FlutterError.onError = (FlutterErrorDetails details) async {
    new ErrorLogger().logError(details);
  };
  runZoned<Future<void>>(() async {
    // Your App Here
    runApp(MainApp());
  }, onError: (error, stackTrace) {
    new ErrorLogger().log(error, stackTrace);
  });
}

logging.dart:

class ErrorLogger {

  void logError(FlutterErrorDetails details) async {
    //FlutterError.dumpErrorToConsole(details);
    _sendToServer(details.exceptionAsString(), details.stack.toString());
  }

  void log(Object data, StackTrace stackTrace) async {  
      // print(data);
      // print(stackTrace);
    _sendToServer(data.toString(), stackTrace.toString());
  }

  void _sendToServer(String a, String b) async {
    // Implementation here
  }
}
Taufiq Rahman
  • 5,600
  • 2
  • 36
  • 44
EderBaum
  • 993
  • 13
  • 16
  • 3
    The original question is more about widget testing and custom errors rather than logging errors from source code. As `expect` doesn't work and `FlutterError.onError` is recommendend with `expectAsync0`, the answer should be consistant with the way a custom error can be tested in widget unit tests. – Muldec Jun 05 '19 at 14:43
  • Could you explain why is the `runZoned` needed here, please? – Sprint Mar 18 '23 at 05:29
  • RunZoned Works like a "try/catch". Here more details: https://stackoverflow.com/questions/21531924/the-purpose-of-function-runzoned-of-dartasync – EderBaum Mar 19 '23 at 13:49
4

This is was design for a test. I switched to wrapping logic in try/catch then running expect() on the "error message text" present concept. ex:

try {
   throw new UnrecognizedTermException();
 } catch (e) {
   setState(() => _status = e.errMsg());
}

// then in my test
expect(find.text('Could not determine the type of item you scanned'), findsOneWidget);
xpeldev
  • 1,812
  • 2
  • 12
  • 23
  • So if I understrand correctly, you managed the exception in your app and stopped trying to catch it in your tests. Is that right ? – Muldec Jun 11 '19 at 09:40
  • Yes that is correct. Im checking for the "behavior" or "artifacts" of my custom exception rather than the exception itself – xpeldev Jun 11 '19 at 13:03
  • Ok. I'd be interrested to know if there's actually a solution to the problem you explained in your question, or if the only way to do this is through a workaround. I'm in a quite similar situation and don't want to loose the Exception by catching it. – Muldec Jun 12 '19 at 07:36