@@ -109,13 +109,24 @@ void main() {
109
109
110
110
await tapMe (tester, sut, 'btn_1' );
111
111
112
- Breadcrumb ? crumb;
113
- fixture.hub.configureScope ((scope) {
114
- crumb = scope.breadcrumbs.last;
115
- });
116
- expect (crumb? .category, 'ui.click' );
117
- expect (crumb? .data? ['view.id' ], 'btn_1' );
118
- expect (crumb? .data? ['view.class' ], 'MaterialButton' );
112
+ expect (
113
+ fixture.getBreadcrumb ().data? .replaceHashCodes (),
114
+ equals ({
115
+ 'path' : [
116
+ {'name' : 'btn_1' , 'element' : 'MaterialButton' },
117
+ {'element' : 'Column' },
118
+ {'element' : 'Center' },
119
+ {'name' : '[GlobalKey#00000]' , 'element' : 'KeyedSubtree' },
120
+ {'element' : 'MediaQuery' },
121
+ {'name' : '_ScaffoldSlot.body' , 'element' : 'LayoutId' },
122
+ {'element' : 'CustomMultiChildLayout' },
123
+ {'element' : 'Actions' },
124
+ {'element' : 'AnimatedBuilder' },
125
+ {'element' : 'DefaultTextStyle' }
126
+ ],
127
+ 'view.id' : 'btn_1' ,
128
+ 'view.class' : 'MaterialButton' ,
129
+ }));
119
130
});
120
131
});
121
132
@@ -125,11 +136,25 @@ void main() {
125
136
126
137
await tapMe (tester, sut, 'btn_1' );
127
138
128
- Breadcrumb ? crumb;
129
- fixture.hub.configureScope ((scope) {
130
- crumb = scope.breadcrumbs.last;
131
- });
132
- expect (crumb? .data? ['label' ], 'Button 1' );
139
+ expect (
140
+ fixture.getBreadcrumb ().data? .replaceHashCodes (),
141
+ equals ({
142
+ 'path' : [
143
+ {'name' : 'btn_1' , 'element' : 'MaterialButton' },
144
+ {'element' : 'Column' },
145
+ {'element' : 'Center' },
146
+ {'name' : '[GlobalKey#00000]' , 'element' : 'KeyedSubtree' },
147
+ {'element' : 'MediaQuery' },
148
+ {'name' : '_ScaffoldSlot.body' , 'element' : 'LayoutId' },
149
+ {'element' : 'CustomMultiChildLayout' },
150
+ {'element' : 'Actions' },
151
+ {'element' : 'AnimatedBuilder' },
152
+ {'element' : 'DefaultTextStyle' }
153
+ ],
154
+ 'label' : 'Button 1' ,
155
+ 'view.id' : 'btn_1' ,
156
+ 'view.class' : 'MaterialButton'
157
+ }));
133
158
});
134
159
});
135
160
@@ -139,11 +164,25 @@ void main() {
139
164
140
165
await tapMe (tester, sut, 'btn_3' );
141
166
142
- Breadcrumb ? crumb;
143
- fixture.hub.configureScope ((scope) {
144
- crumb = scope.breadcrumbs.last;
145
- });
146
- expect (crumb? .data? ['label' ], 'My Icon' );
167
+ expect (
168
+ fixture.getBreadcrumb ().data? .replaceHashCodes (),
169
+ equals ({
170
+ 'path' : [
171
+ {'name' : 'btn_3' , 'element' : 'IconButton' },
172
+ {'element' : 'Column' },
173
+ {'element' : 'Center' },
174
+ {'name' : '[GlobalKey#00000]' , 'element' : 'KeyedSubtree' },
175
+ {'element' : 'MediaQuery' },
176
+ {'name' : '_ScaffoldSlot.body' , 'element' : 'LayoutId' },
177
+ {'element' : 'CustomMultiChildLayout' },
178
+ {'element' : 'Actions' },
179
+ {'element' : 'AnimatedBuilder' },
180
+ {'element' : 'DefaultTextStyle' }
181
+ ],
182
+ 'label' : 'My Icon' ,
183
+ 'view.id' : 'btn_3' ,
184
+ 'view.class' : 'IconButton'
185
+ }));
147
186
});
148
187
});
149
188
@@ -153,11 +192,25 @@ void main() {
153
192
154
193
await tapMe (tester, sut, 'btn_2' );
155
194
156
- Breadcrumb ? crumb;
157
- fixture.hub.configureScope ((scope) {
158
- crumb = scope.breadcrumbs.last;
159
- });
160
- expect (crumb? .data? ['label' ], 'Button 2' );
195
+ expect (
196
+ fixture.getBreadcrumb ().data? .replaceHashCodes (),
197
+ equals ({
198
+ 'path' : [
199
+ {'name' : 'btn_2' , 'element' : 'CupertinoButton' },
200
+ {'element' : 'Column' },
201
+ {'element' : 'Center' },
202
+ {'name' : '[GlobalKey#00000]' , 'element' : 'KeyedSubtree' },
203
+ {'element' : 'MediaQuery' },
204
+ {'name' : '_ScaffoldSlot.body' , 'element' : 'LayoutId' },
205
+ {'element' : 'CustomMultiChildLayout' },
206
+ {'element' : 'Actions' },
207
+ {'element' : 'AnimatedBuilder' },
208
+ {'element' : 'DefaultTextStyle' }
209
+ ],
210
+ 'label' : 'Button 2' ,
211
+ 'view.id' : 'btn_2' ,
212
+ 'view.class' : 'CupertinoButton'
213
+ }));
161
214
});
162
215
});
163
216
@@ -183,11 +236,25 @@ void main() {
183
236
184
237
await tapMe (tester, sut, 'btn_5' );
185
238
186
- Breadcrumb ? crumb;
187
- fixture.hub.configureScope ((scope) {
188
- crumb = scope.breadcrumbs.last;
189
- });
190
- expect (crumb? .data? ['label' ], 'Button 5' );
239
+ expect (
240
+ fixture.getBreadcrumb ().data? .replaceHashCodes (),
241
+ equals ({
242
+ 'path' : [
243
+ {'name' : 'btn_5' , 'element' : 'ButtonStyleButton' },
244
+ {'element' : 'Stack' },
245
+ {'element' : 'Listener' },
246
+ {'element' : 'RawGestureDetector' },
247
+ {'name' : 'btn_4' , 'element' : 'GestureDetector' },
248
+ {'element' : 'Semantics' },
249
+ {'element' : 'DefaultTextStyle' },
250
+ {'element' : 'AnimatedDefaultTextStyle' },
251
+ {'element' : 'NotificationListener<LayoutChangedNotification>' },
252
+ {'element' : 'CustomPaint' }
253
+ ],
254
+ 'label' : 'Button 5' ,
255
+ 'view.id' : 'btn_5' ,
256
+ 'view.class' : 'ButtonStyleButton'
257
+ }));
191
258
});
192
259
});
193
260
@@ -197,13 +264,24 @@ void main() {
197
264
198
265
await tapMe (tester, sut, 'popup_menu_button' );
199
266
200
- Breadcrumb ? crumb;
201
- fixture.hub.configureScope ((scope) {
202
- crumb = scope.breadcrumbs.last;
203
- });
204
- expect (crumb? .category, 'ui.click' );
205
- expect (crumb? .data? ['view.id' ], 'popup_menu_button' );
206
- expect (crumb? .data? ['view.class' ], 'PopupMenuButton' );
267
+ expect (
268
+ fixture.getBreadcrumb ().data? .replaceHashCodes (),
269
+ equals ({
270
+ 'path' : [
271
+ {'name' : 'popup_menu_button' , 'element' : 'PopupMenuButton' },
272
+ {'element' : 'Column' },
273
+ {'element' : 'Center' },
274
+ {'name' : '[GlobalKey#00000]' , 'element' : 'KeyedSubtree' },
275
+ {'element' : 'MediaQuery' },
276
+ {'name' : '_ScaffoldSlot.body' , 'element' : 'LayoutId' },
277
+ {'element' : 'CustomMultiChildLayout' },
278
+ {'element' : 'Actions' },
279
+ {'element' : 'AnimatedBuilder' },
280
+ {'element' : 'DefaultTextStyle' }
281
+ ],
282
+ 'view.id' : 'popup_menu_button' ,
283
+ 'view.class' : 'PopupMenuButton'
284
+ }));
207
285
});
208
286
});
209
287
@@ -217,13 +295,56 @@ void main() {
217
295
218
296
await tapMe (tester, sut, 'popup_menu_item_1' );
219
297
220
- Breadcrumb ? crumb;
221
- fixture.hub.configureScope ((scope) {
222
- crumb = scope.breadcrumbs.last;
223
- });
224
- expect (crumb? .category, 'ui.click' );
225
- expect (crumb? .data? ['view.id' ], 'popup_menu_item_1' );
226
- expect (crumb? .data? ['view.class' ], 'PopupMenuItem' );
298
+ expect (
299
+ fixture.getBreadcrumb ().data? .replaceHashCodes (),
300
+ equals ({
301
+ 'path' : [
302
+ {'name' : 'popup_menu_item_1' , 'element' : 'PopupMenuItem' },
303
+ {'name' : '[GlobalKey#00000]' , 'element' : 'FadeTransition' },
304
+ {'element' : 'ListBody' },
305
+ {'element' : 'Padding' },
306
+ {'name' : '[GlobalKey#00000]' , 'element' : 'IgnorePointer' },
307
+ {'element' : 'Semantics' },
308
+ {'element' : 'Listener' },
309
+ {
310
+ 'name' : '[LabeledGlobalKey<RawGestureDetectorState>#00000]' ,
311
+ 'element' : 'RawGestureDetector'
312
+ },
313
+ {'element' : 'Listener' },
314
+ {'element' : 'NotificationListener<ScrollMetricsNotification>' }
315
+ ],
316
+ 'view.id' : 'popup_menu_item_1' ,
317
+ 'view.class' : 'PopupMenuItem'
318
+ }));
319
+ });
320
+ });
321
+
322
+ testWidgets ('Add crumb for button with tooltip' , (tester) async {
323
+ await tester.runAsync (() async {
324
+ final sut = fixture.getSut (sendDefaultPii: true );
325
+
326
+ // open the popup menu and wait for the animation to complete
327
+ await tapMe (tester, sut, 'tooltip_button' );
328
+
329
+ expect (
330
+ fixture.getBreadcrumb ().data? .replaceHashCodes (),
331
+ equals ({
332
+ 'path' : [
333
+ {'name' : 'tooltip_button' , 'element' : 'ButtonStyleButton' },
334
+ {'element' : 'Semantics' },
335
+ {'element' : 'Listener' },
336
+ {'element' : 'OverlayPortal' },
337
+ {'element' : 'Tooltip' , 'label' : 'Tooltip message.' },
338
+ {'element' : 'Column' },
339
+ {'element' : 'Center' },
340
+ {'name' : '[GlobalKey#00000]' , 'element' : 'KeyedSubtree' },
341
+ {'element' : 'MediaQuery' },
342
+ {'name' : '_ScaffoldSlot.body' , 'element' : 'LayoutId' }
343
+ ],
344
+ 'label' : 'Button text' ,
345
+ 'view.id' : 'tooltip_button' ,
346
+ 'view.class' : 'ButtonStyleButton'
347
+ }));
227
348
});
228
349
});
229
350
});
@@ -394,6 +515,14 @@ class Fixture {
394
515
child: MyApp (),
395
516
);
396
517
}
518
+
519
+ Breadcrumb getBreadcrumb () {
520
+ late final Breadcrumb crumb;
521
+ hub.configureScope ((scope) {
522
+ crumb = scope.breadcrumbs.last;
523
+ });
524
+ return crumb;
525
+ }
397
526
}
398
527
399
528
class MyApp extends StatelessWidget {
@@ -420,23 +549,17 @@ class Page1 extends StatelessWidget {
420
549
children: [
421
550
MaterialButton (
422
551
key: Key ('btn_1' ),
423
- onPressed: () {
424
- // print('button pressed');
425
- },
552
+ onPressed: () {},
426
553
child: const Text ('Button 1' ),
427
554
),
428
555
CupertinoButton (
429
556
key: Key ('btn_2' ),
430
- onPressed: () {
431
- // print('button pressed 2');
432
- },
557
+ onPressed: () {},
433
558
child: const Text ('Button 2' ),
434
559
),
435
560
IconButton (
436
561
key: Key ('btn_3' ),
437
- onPressed: () {
438
- // print('button pressed 3');
439
- },
562
+ onPressed: () {},
440
563
icon: Icon (
441
564
Icons .dark_mode,
442
565
semanticLabel: 'My Icon' ,
@@ -445,17 +568,13 @@ class Page1 extends StatelessWidget {
445
568
Card (
446
569
child: GestureDetector (
447
570
key: Key ('btn_4' ),
448
- onTap: () => {
449
- // print('button pressed 4'),
450
- },
571
+ onTap: () => {},
451
572
child: Stack (
452
573
children: [
453
574
//fancy card layout
454
575
ElevatedButton (
455
576
key: Key ('btn_5' ),
456
- onPressed: () => {
457
- // print('button pressed 5'),
458
- },
577
+ onPressed: () => {},
459
578
child: const Text ('Button 5' ),
460
579
),
461
580
],
@@ -478,6 +597,14 @@ class Page1 extends StatelessWidget {
478
597
),
479
598
],
480
599
),
600
+ Tooltip (
601
+ message: 'Tooltip message.' ,
602
+ child: ElevatedButton (
603
+ key: ValueKey ('tooltip_button' ),
604
+ onPressed: () {},
605
+ child: Text ('Button text' ),
606
+ ),
607
+ )
481
608
],
482
609
),
483
610
),
@@ -496,9 +623,7 @@ class Page2 extends StatelessWidget {
496
623
children: [
497
624
MaterialButton (
498
625
key: Key ('btn_page_2' ),
499
- onPressed: () {
500
- // print('button page 2 pressed');
501
- },
626
+ onPressed: () {},
502
627
child: const Text ('Button Page 2' ),
503
628
),
504
629
],
@@ -507,3 +632,34 @@ class Page2 extends StatelessWidget {
507
632
);
508
633
}
509
634
}
635
+
636
+ extension on String {
637
+ String replaceHashCodes () => replaceAll (RegExp (r'#[\da-fA-F]{5}' ), '#00000' );
638
+ }
639
+
640
+ extension on Map <dynamic , dynamic > {
641
+ Map <dynamic , dynamic > replaceHashCodes () => map ((key, value) {
642
+ if (value is String ) {
643
+ value = value.replaceHashCodes ();
644
+ } else if (value is Map ) {
645
+ value = value.replaceHashCodes ();
646
+ } else if (value is List ) {
647
+ value = value.replaceHashCodes ();
648
+ }
649
+ return MapEntry (key, value);
650
+ });
651
+ }
652
+
653
+ extension on List <dynamic > {
654
+ Iterable <dynamic > replaceHashCodes () => map ((value) {
655
+ if (value is String ) {
656
+ return value.replaceHashCodes ();
657
+ } else if (value is Map ) {
658
+ return value.replaceHashCodes ();
659
+ } else if (value is List ) {
660
+ return value.replaceHashCodes ();
661
+ } else {
662
+ return value;
663
+ }
664
+ });
665
+ }
0 commit comments