Flutter Widget Testing Cheatsheet
(c) Написано с использованием нейросетей ChatGPT 5
Минимальный набор вещей, которые стоит знать при написании виджет-тестов.
1. Основные пакеты
dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';2. Запуск теста
dart
testWidgets('description', (WidgetTester tester) async {
await tester.pumpWidget(MyWidget());
});tester.pumpWidget()— строит дерево виджетов.tester.pump()— перерисовка дерева (один кадр).tester.pumpAndSettle()— ждёт окончания всех анимаций и микротасков.
3. Поиск виджетов
find.byType(MyWidget)— ищет виджет по типу.find.text('Hello')— ищет текст.find.byKey(ValueKey('myKey'))— ищет виджет по ключу.find.byWidgetPredicate((w) => w is MyWidget)— гибкий поиск по условию.- Важно:
find.byWidget(widgetInstance)ищет точно этот объект, почти не используют.
4. Взаимодействие с виджетами
await tester.tap(finder)— тап по виджету.await tester.enterText(finder, 'text')— ввод текста.await tester.drag(finder, Offset(dx, dy))— свайп/драг.- Добавлять
await tester.pump()после действий, чтобы обновить дерево.
⚡ Для ожидаемого игнорирования событий:
dart
await tester.tap(finder, warnIfMissed: false);5. Проверки
dart
expect(find.text('Hello'), findsOneWidget);
expect(find.byType(MyWidget), findsNothing);
expect(find.byKey(ValueKey('myKey')), findsWidgets); // несколькоfindsOneWidget,findsNothing,findsWidgets— основные матчеры.
6. Ключи (Key)
- Очень полезны для поиска конкретного виджета среди нескольких одинаковых.
- Использовать
ValueKey,UniqueKeyили кастомные ключи. - Пример:
dart
FFTIconButton.standard(
key: ValueKey('close-button'),
...
)7. Работа с состоянием
- Если виджет использует
setStateилиProvider/BLoC, нужно вызватьpump()после изменения состояния:
dart
myState.toggleFlag();
await tester.pump();- Для анимаций:
dart
await tester.pumpAndSettle(); // ждём завершения всех анимаций8. Приватные фабричные подклассы
Если виджет создаётся через factory + приватный подкласс:
dart
sealed class A extends StatelessWidget { ... }
class _A extends A { ... }find.byType(A)не сработает, потому что реально создаётся_A.- Решения:
dart
find.byWidgetPredicate((w) => w is A)
find.byKey(ValueKey('some-key'))9. Игнорирование и проверка взаимодействий
IgnorePointer/AbsorbPointerблокируют события:
dart
final ignore = tester.widget<IgnorePointer>(
find.ancestor(of: finder, matching: find.byType(IgnorePointer))
);
expect(ignore.ignoring, true);- Можно безопасно тапать с
warnIfMissed: falseв таких случаях.
10. Ассеты в тестах
- Если виджет грузит ассеты (
rootBundle.loadString):- Положить тестовые ассеты в
test/assets/.... - Добавить их в
pubspec.yaml. - Загружать через:
- Положить тестовые ассеты в
dart
final jsonStr = await rootBundle.loadString('test/assets/test_tokens.json');
tokens = FFTokens.fromJson(jsonDecode(jsonStr));- Альтернатива: мокнуть токены или использовать дефолтные значения (
FFTokens.fallback()).
11. Полезные советы
- Комбинируй
find.byType+byKeyдля надёжного поиска. - Всегда
pump()после изменения состояния. - Для анимаций и появления/скрытия —
pumpAndSettle(). - Добавляй ключи на важные элементы (кнопки, текст, контейнеры).
- Используй
WidgetPredicate, если работаешь с приватными фабричными подклассами. - Для ожидаемых неудачных тапов —
warnIfMissed: false.