Skip to content

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.