1
+ // Copyright 2014 The Flutter Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import 'dart:async' ;
6
+ import 'dart:convert' ;
7
+
8
+ import 'package:flutter/foundation.dart' ;
9
+ import 'package:flutter/rendering.dart' ;
10
+ import 'package:flutter/widgets.dart' ;
11
+ import 'package:flutter_test/flutter_test.dart' ;
12
+
13
+ void main () {
14
+ StructureErrorTestWidgetInspectorService .runTests ();
15
+ }
16
+
17
+ typedef InspectorServiceExtensionCallback = FutureOr <Map <String , Object >> Function (Map <String , String > parameters);
18
+
19
+ class StructureErrorTestWidgetInspectorService extends Object with WidgetInspectorService {
20
+ final Map <String , InspectorServiceExtensionCallback > extensions = < String , InspectorServiceExtensionCallback > {};
21
+
22
+ final Map <String , List <Map <Object , Object >>> eventsDispatched = < String , List <Map <Object , Object >>> {};
23
+
24
+ @override
25
+ void registerServiceExtension ({
26
+ @required String name,
27
+ @required FutureOr <Map <String , Object >> callback (Map <String , String > parameters),
28
+ }) {
29
+ assert (! extensions.containsKey (name));
30
+ extensions[name] = callback;
31
+ }
32
+
33
+ @override
34
+ void postEvent (String eventKind, Map <Object , Object > eventData) {
35
+ getEventsDispatched (eventKind).add (eventData);
36
+ }
37
+
38
+ List <Map <Object , Object >> getEventsDispatched (String eventKind) {
39
+ return eventsDispatched.putIfAbsent (eventKind, () => < Map <Object , Object >> []);
40
+ }
41
+
42
+ Iterable <Map <Object , Object >> getServiceExtensionStateChangedEvents (String extensionName) {
43
+ return getEventsDispatched ('Flutter.ServiceExtensionStateChanged' )
44
+ .where ((Map <Object , Object > event) => event['extension' ] == extensionName);
45
+ }
46
+
47
+ Future <String > testBoolExtension (String name, Map <String , String > arguments) async {
48
+ expect (extensions, contains (name));
49
+ // Encode and decode to JSON to match behavior using a real service
50
+ // extension where only JSON is allowed.
51
+ return json.decode (json.encode (await extensions[name](arguments)))['enabled' ] as String ;
52
+ }
53
+
54
+
55
+ static void runTests () {
56
+ final StructureErrorTestWidgetInspectorService service = StructureErrorTestWidgetInspectorService ();
57
+ WidgetInspectorService .instance = service;
58
+
59
+ test ('ext.flutter.inspector.structuredErrors still report error to original on error' , () async {
60
+ final FlutterExceptionHandler oldHandler = FlutterError .onError;
61
+
62
+ FlutterErrorDetails actualError;
63
+ // Creates a spy onError. This spy needs to be set before widgets binding
64
+ // initializes.
65
+ FlutterError .onError = (FlutterErrorDetails details) {
66
+ actualError = details;
67
+ };
68
+
69
+ WidgetsFlutterBinding .ensureInitialized ();
70
+ try {
71
+ // Enables structured errors.
72
+ expect (await service.testBoolExtension (
73
+ 'structuredErrors' , < String , String > {'enabled' : 'true' }),
74
+ equals ('true' ));
75
+
76
+ // Creates an error.
77
+ final FlutterErrorDetails expectedError = FlutterErrorDetailsForRendering (
78
+ library: 'rendering library' ,
79
+ context: ErrorDescription ('during layout' ),
80
+ exception: StackTrace .current,
81
+ );
82
+ FlutterError .reportError (expectedError);
83
+
84
+ // Validates the spy still received an error.
85
+ expect (actualError, expectedError);
86
+ } finally {
87
+ FlutterError .onError = oldHandler;
88
+ }
89
+ });
90
+ }
91
+ }
0 commit comments