Skip to content

Commit

Permalink
Show partial tap warning in timline (#69)
Browse files Browse the repository at this point in the history
  • Loading branch information
passsy authored Nov 12, 2024
1 parent 9b2ede1 commit 6da4051
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 30 deletions.
44 changes: 24 additions & 20 deletions lib/src/act/act.dart
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,12 @@ class Act {
);
return;
}
_reportPartialCoverage(pokablePositions, snapshot);
final partialWarning =
_createPartialCoverageMessage(pokablePositions, snapshot);
if (partialWarning != null) {
// ignore: avoid_print
print(partialWarning);
}

final positionToTap = pokablePositions.mostCenterHittablePosition!;
final binding = TestWidgetsFlutterBinding.instance;
Expand All @@ -117,11 +122,12 @@ class Act {
CrosshairAnnotator(centerPosition: positionToTap),
],
);
final partial = partialWarning == null ? '' : '\n$partialWarning';
timeline.addEvent(
details: 'Tap ${selector.toStringBreadcrumb()}',
eventType: 'Tap Event',
details: 'Tap ${selector.toStringBreadcrumb()}$partial',
screenshot: screenshot,
color: Colors.blue,
color: partialWarning == null ? Colors.blue : Colors.purple,
);
}

Expand Down Expand Up @@ -190,7 +196,7 @@ class Act {
);
return;
}
_reportPartialCoverage(pokablePositions, snapshot);
_createPartialCoverageMessage(pokablePositions, snapshot);
final targetName = dragTarget.toStringBreadcrumb();

bool isTargetVisible() {
Expand Down Expand Up @@ -330,30 +336,28 @@ class Act {
}

/// Throws a warning when the widget is only partially reacting to tap events
void _reportPartialCoverage(
String? _createPartialCoverageMessage(
_PokablePositions pokablePositions,
WidgetSnapshot snapshot,
) {
final roundUp = pokablePositions.percent.ceil();
if (roundUp > 80) {
// Don't be pedantic when the widget is almost fully tappable
return;
return null;
}
// ignore: avoid_print
print(
"Warning: The '${snapshot.discoveredWidget!.toStringShort()}' is only partially reacting to tap events. "
"Only ~$roundUp% of the widget reacts to hitTest events.\n"
"\n"
"Possible causes:"
" - The widget is partially positioned out of view\n"
" - It is covered by another widget.\n"
" - It is too small (<8x8)\n"
"\n"
"Possible solutions:\n"
" - Scroll the widget into view using act.dragUntilVisible()\n"
" - Make sure no other Widget is overlapping on small screens\n"
" - Increase the Widget size\n",
);
return "Warning: The '${snapshot.discoveredWidget!.toStringShort()}' is only partially reacting to tap events. "
"Only ~$roundUp% of the widget reacts to hitTest events.\n"
"\n"
"Possible causes:\n"
" - The widget is partially positioned out of view\n"
" - It is covered by another widget.\n"
" - It is too small (<8x8)\n"
"\n"
"Possible solutions:\n"
" - Scroll the widget into view using act.dragUntilVisible()\n"
" - Make sure no other Widget is overlapping on small screens\n"
" - Increase the Widget size\n";
}

/// Checks if the widget is visible and not covered by another widget
Expand Down
14 changes: 8 additions & 6 deletions lib/src/screenshot/screenshot_annotator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ class HighlightAnnotator implements ScreenshotAnnotator {
/// Highlight plain rectangles on the screenshot with optional labels.
HighlightAnnotator.rects(
this.rects, {
this.color = const Color(0xFFFF00FF),
this.color,
this.labels,
}) : assert(labels == null || rects.length == labels.length);

/// Highlight elements on the screenshot
factory HighlightAnnotator.elements(List<Element> elements) {
factory HighlightAnnotator.elements(List<Element> elements, {Color? color}) {
final binding = TestWidgetsFlutterBinding.instance;
final view = binding.platformDispatcher.implicitView;
final devicePixelRatio = view?.devicePixelRatio ?? 1.0;
Expand All @@ -137,12 +137,12 @@ class HighlightAnnotator implements ScreenshotAnnotator {
);
labels.add('${element.toStringShort()} #$index');
}
return HighlightAnnotator.rects(rects, labels: labels);
return HighlightAnnotator.rects(rects, labels: labels, color: color);
}

/// Highlight a single element on the screenshot
factory HighlightAnnotator.element(Element element) {
return HighlightAnnotator.elements([element]);
factory HighlightAnnotator.element(Element element, {Color? color}) {
return HighlightAnnotator.elements([element], color: color);
}

/// The rectangles to highlight. They are captured at the point of creation,
Expand All @@ -153,7 +153,7 @@ class HighlightAnnotator implements ScreenshotAnnotator {
final List<String>? labels;

/// The color to use for highlighting.
final Color color;
final Color? color;

@override
String get name => 'Highlight Elements Annotator';
Expand All @@ -173,6 +173,8 @@ class HighlightAnnotator implements ScreenshotAnnotator {

canvas.drawImage(image, Offset.zero, Paint());

final color = this.color ?? const Color(0xFFFF00FF);

final paint = Paint()
..color = color
..style = PaintingStyle.stroke
Expand Down
5 changes: 3 additions & 2 deletions lib/src/spot/snapshot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -591,12 +591,13 @@ void _tryMatchingLessSpecificCriteria(WidgetSnapshot snapshot) {
annotators: [
HighlightAnnotator.elements(
lessSpecificSnapshot.discoveredElements,
color: Colors.cyan,
),
],
);
timeline.addEvent(
eventType: 'Assertion',
color: Colors.grey,
eventType: 'Assertion Failed',
color: Colors.red,
screenshot: screenshot,
details: '$errorBuilder\nFound in widget Tree:\n$significantTree',
);
Expand Down
51 changes: 49 additions & 2 deletions test/act/find_tappable_area_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ void main() {
lines,
startsWith(
"Warning: The '_TestButton' is only partially reacting to tap events. Only ~7% of the widget reacts to hitTest events.\n"
'Possible causes: - The widget is partially positioned out of view\n'
'Possible causes:\n'
' - The widget is partially positioned out of view\n'
' - It is covered by another widget.\n'
' - It is too small (<8x8)\n'
'Possible solutions:\n'
Expand All @@ -107,6 +108,51 @@ void main() {
);
});

testWidgets(
'Warn about using and finding alternative tappable area in timeline',
(tester) async {
bool tapped = false;
await tester.pumpWidget(
MaterialApp(
home: PokeTestWidget(
columns: 5,
rows: 5,
pokableAtColumnIndex: 4,
pokableAtRowIndex: 4,
widgetToCover: _TestButton(
onTap: () {
tapped = !tapped;
},
),
),
),
);
final WidgetSelector button = spot<_TestButton>()..existsOnce();

await act.tap(button);

expect(tapped, isTrue);
final last = timeline.events.last;
expect(last.eventType.label, 'Tap Event');
expect(
last.details,
contains(
"Warning: The '_TestButton' is only partially reacting to tap events. Only ~7% of the widget reacts to hitTest events.\n"
'\n'
'Possible causes:\n'
' - The widget is partially positioned out of view\n'
' - It is covered by another widget.\n'
' - It is too small (<8x8)\n'
'\n'
'Possible solutions:\n'
' - Scroll the widget into view using act.dragUntilVisible()\n'
' - Make sure no other Widget is overlapping on small screens\n'
' - Increase the Widget size',
),
);
expect(last.eventType.color, Colors.purple);
});

testWidgets('Center of widget not tappable, finds alternative tappable area.',
(tester) async {
bool tapped = false;
Expand Down Expand Up @@ -150,7 +196,8 @@ void main() {
lines,
contains(
"Warning: The '_TestButton' is only partially reacting to tap events. Only ~67% of the widget reacts to hitTest events.\n"
'Possible causes: - The widget is partially positioned out of view\n'
'Possible causes:\n'
' - The widget is partially positioned out of view\n'
' - It is covered by another widget.\n'
' - It is too small (<8x8)\n'
'Possible solutions:\n'
Expand Down

0 comments on commit 6da4051

Please sign in to comment.