Skip to content

Instantly share code, notes, and snippets.

@KoalityJustin
Last active December 26, 2023 06:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KoalityJustin/910c9a5dd1ddb43c34de9770f4dac11f to your computer and use it in GitHub Desktop.
Save KoalityJustin/910c9a5dd1ddb43c34de9770f4dac11f to your computer and use it in GitHub Desktop.
All You Need
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
extension TestingHelpers on WidgetTester {
/// Helper method for tapping a finder, and for optionally choosing the index
/// if the finder finds multiple and if we should scroll to before tapping.
Future<void> tapFinder(
Finder finder, {
int index = 0,
bool scrollTo = false,
bool useScrollable = false,
bool warnIfMissed = false,
}) async {
expect(finder, findsWidgets);
final maxIndex = min(index, finder.evaluate().length - 1);
final honedFinder = finder.at(maxIndex);
if (scrollTo) {
await ensureVisible(honedFinder);
await pumpAndSettle();
}
if (useScrollable) {
final scrollable = find.byType(Scrollable).first;
await scrollUntilVisible(honedFinder, 300, scrollable: scrollable);
await pumpAndSettle();
}
await tap(honedFinder, warnIfMissed: warnIfMissed);
await pumpAndSettle();
}
Future<void> tapKey(
String keyName, {
int index = 0,
bool scrollTo = true,
bool useScrollable = false,
bool skipOffstage = false,
}) async {
final finder = find.byKey(ValueKey(keyName), skipOffstage: skipOffstage);
await tapFinder(
finder,
index: index,
scrollTo: scrollTo,
useScrollable: useScrollable,
);
}
Future<void> tapText(
String text, {
int index = 0,
bool scrollTo = true,
bool useScrollable = false,
bool skipOffstage = false,
}) async {
final finder = find.text(text, skipOffstage: skipOffstage);
await tapFinder(
finder,
index: index,
scrollTo: scrollTo,
useScrollable: useScrollable,
);
}
Future<void> tapIcon(
IconData icon, {
int index = 0,
bool scrollTo = false,
bool useScrollable = false,
bool skipOffstage = false,
}) async {
final finder = find.byIcon(icon, skipOffstage: skipOffstage);
await tapFinder(
finder,
index: index,
scrollTo: scrollTo,
useScrollable: useScrollable,
);
}
Future<void> tapBackButton({bool skipOffstage = false}) async {
final finder = find.byType(BackButton, skipOffstage: skipOffstage);
await tapFinder(finder);
}
Future<void> wait(int ms) async {
await Future<void>.delayed(Duration(milliseconds: ms));
}
Future<void> waitFor(
Finder finder, {
Duration interval = const Duration(milliseconds: 16),
Duration timeout = const Duration(seconds: 10),
Matcher matcher = findsWidgets,
bool immediateCheck = false,
bool scrollTo = true,
bool useScrollable = false,
int index = 0,
}) async {
final stopwatch = Stopwatch()..start();
// If our matcher is to NOT find anything, we want to wait the interval once
// and then check.
if (immediateCheck) {
await pumpAndSettle();
await Future<void>.delayed(interval);
expect(finder, matcher);
return;
} else {
while (stopwatch.elapsed < timeout) {
await Future<void>.delayed(interval);
await pump();
final foundSomething = finder.evaluate().isNotEmpty;
if (foundSomething) {
await findIt(
finder: finder,
interval: interval,
scrollTo: scrollTo,
useScrollable: useScrollable,
index: index,
);
expect(finder, matcher);
stopwatch.stop();
return;
}
}
}
expect(finder, matcher);
}
Future<void> waitForText(
String text, {
Duration interval = const Duration(milliseconds: 16),
Duration timeout = const Duration(seconds: 10),
Matcher matcher = findsWidgets,
bool skipOffstage = true,
bool immediateCheck = false,
bool scrollTo = true,
bool useScrollable = false,
int index = 0,
}) async {
final stopwatch = Stopwatch()..start();
// If our matcher is to NOT find anything, we want to wait the interval once
// and then check.
final finder = find.text(text, skipOffstage: skipOffstage);
if (immediateCheck) {
await pumpAndSettle();
await Future<void>.delayed(interval);
expect(finder, matcher);
return;
} else {
while (stopwatch.elapsed < timeout) {
await Future<void>.delayed(interval);
await pump();
final foundSomething = finder.evaluate().isNotEmpty;
if (foundSomething) {
await findIt(
finder: finder,
interval: interval,
scrollTo: scrollTo,
useScrollable: useScrollable,
index: index,
);
expect(finder, matcher);
stopwatch.stop();
return;
}
}
}
expect(finder, matcher);
}
Future<void> waitForTextContaining(
String text, {
Duration interval = const Duration(milliseconds: 16),
Duration timeout = const Duration(seconds: 10),
Matcher matcher = findsWidgets,
bool skipOffstage = true,
bool immediateCheck = false,
bool scrollTo = true,
bool useScrollable = false,
int index = 0,
}) async {
final stopwatch = Stopwatch()..start();
// If our matcher is to NOT find anything, we want to wait the interval once
// and then check.
final finder = find.textContaining(text, skipOffstage: skipOffstage);
if (immediateCheck) {
await pumpAndSettle();
await Future<void>.delayed(interval);
expect(finder, matcher);
return;
} else {
while (stopwatch.elapsed < timeout) {
await Future<void>.delayed(interval);
await pump();
final foundSomething = finder.evaluate().isNotEmpty;
if (foundSomething) {
await findIt(
finder: finder,
interval: interval,
scrollTo: scrollTo,
useScrollable: useScrollable,
index: index,
);
expect(finder, matcher);
stopwatch.stop();
return;
}
}
}
expect(finder, matcher);
}
Future<void> findIt({
required Finder finder,
required Duration interval,
bool scrollTo = true,
bool useScrollable = false,
int index = 0,
}) async {
if (scrollTo) {
if (useScrollable) {
final scroll = find.byType(Scrollable).first;
await scrollUntilVisible(
finder,
300,
scrollable: scroll,
duration: interval,
);
await pumpAndSettle();
} else {
final maxIndex = min(index, finder.evaluate().length - 1);
final honedFinder = finder.at(maxIndex);
await ensureVisible(honedFinder);
await pumpAndSettle();
}
}
}
Future<void> input(
String text, {
int index = 0,
Finder? finder,
String? key,
bool skipOffstage = false,
TextInputAction? action = TextInputAction.done,
}) async {
late final Finder finder;
if (key != null) {
finder = find.byKey(ValueKey(key), skipOffstage: skipOffstage);
} else {
finder = find.byType(EditableText, skipOffstage: skipOffstage);
}
expect(finder, findsWidgets);
final maxIndex = max(index, finder.evaluate().length - 1);
await tapFinder(finder.at(maxIndex));
await enterText(finder.at(maxIndex), text);
await pump();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment