From d708d9deb2e9afcbbcebd162d6ac629eb895e676 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Tue, 23 Jul 2019 17:01:14 -0700 Subject: [PATCH] add an error count field to the Flutter.Error event (#36768) * add an error count field to the Flutter.Error event * review comments; more tests * normalize comments --- .../lib/src/widgets/widget_inspector.dart | 21 +++++- .../test/widgets/widget_inspector_test.dart | 67 ++++++++++++++++++- 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index d3ba3cd853..23820de1f8 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -908,8 +908,10 @@ mixin WidgetInspectorService { static const String _consoleObjectGroup = 'console-group'; + int _errorsSinceReload = 0; + void _reportError(FlutterErrorDetails details) { - postEvent('Flutter.Error', _nodeToJson( + final Map errorJson = _nodeToJson( details.toDiagnosticsNode(), _SerializationDelegate( groupName: _consoleObjectGroup, @@ -919,7 +921,21 @@ mixin WidgetInspectorService { maxDescendentsTruncatableNode: 5, service: this, ), - )); + ); + + errorJson['errorsSinceReload'] = _errorsSinceReload; + _errorsSinceReload += 1; + + postEvent('Flutter.Error', errorJson); + } + + /// Resets the count of errors since the last hot reload. + /// + /// This data is sent to clients as part of the 'Flutter.Error' service + /// protocol event. Clients may choose to display errors received after the + /// first error differently. + void _resetErrorCount() { + _errorsSinceReload = 0; } /// Called to register service extensions. @@ -1838,6 +1854,7 @@ mixin WidgetInspectorService { /// [BindingBase.reassembleApplication]. void performReassemble() { _clearStats(); + _resetErrorCount(); } } diff --git a/packages/flutter/test/widgets/widget_inspector_test.dart b/packages/flutter/test/widgets/widget_inspector_test.dart index c77591d5c2..dc77bd405c 100644 --- a/packages/flutter/test/widgets/widget_inspector_test.dart +++ b/packages/flutter/test/widgets/widget_inspector_test.dart @@ -8,11 +8,11 @@ import 'dart:math'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter/gestures.dart' show DragStartBehavior; // Start of block of code where widget creation location line numbers and // columns will impact whether tests pass. @@ -2331,6 +2331,71 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService { ); }, skip: isBrowser); + testWidgets('ext.flutter.inspector.structuredErrors', (WidgetTester tester) async { + List> flutterErrorEvents = service.getEventsDispatched('Flutter.Error'); + expect(flutterErrorEvents, isEmpty); + + final FlutterExceptionHandler oldHandler = FlutterError.onError; + + try { + // Enable structured errors. + expect(await service.testBoolExtension( + 'structuredErrors', {'enabled': 'true'}), + equals('true')); + + // Create an error. + FlutterError.reportError(FlutterErrorDetailsForRendering( + library: 'rendering library', + context: ErrorDescription('during layout'), + exception: StackTrace.current, + )); + + // Validate that we received an error. + flutterErrorEvents = service.getEventsDispatched('Flutter.Error'); + expect(flutterErrorEvents, hasLength(1)); + + // Validate the error contents. + Map error = flutterErrorEvents.first; + expect(error['description'], 'Exception caught by rendering library'); + expect(error['children'], isEmpty); + + // Validate that we received an error count. + expect(error['errorsSinceReload'], 0); + + // Send a second error. + FlutterError.reportError(FlutterErrorDetailsForRendering( + library: 'rendering library', + context: ErrorDescription('also during layout'), + exception: StackTrace.current, + )); + + // Validate that the error count increased. + flutterErrorEvents = service.getEventsDispatched('Flutter.Error'); + expect(flutterErrorEvents, hasLength(2)); + error = flutterErrorEvents.last; + expect(error['errorsSinceReload'], 1); + + // Reload the app. + tester.binding.reassembleApplication(); + await tester.pump(); + + // Send another error. + FlutterError.reportError(FlutterErrorDetailsForRendering( + library: 'rendering library', + context: ErrorDescription('during layout'), + exception: StackTrace.current, + )); + + // And, validate that the error count has been reset. + flutterErrorEvents = service.getEventsDispatched('Flutter.Error'); + expect(flutterErrorEvents, hasLength(3)); + error = flutterErrorEvents.last; + expect(error['errorsSinceReload'], 0); + } finally { + FlutterError.onError = oldHandler; + } + }); + testWidgets('Screenshot of composited transforms - only offsets', (WidgetTester tester) async { // Composited transforms are challenging to take screenshots of as the // LeaderLayer and FollowerLayer classes used by CompositedTransformTarget