Flutter

flutter pub add dev:tracera_flutter

Требуются Dart ≥ 3.8 и Flutter ≥ 3.24 (см. Адаптеры автотестов). tracera_flutter на pub.dev.

Переменные окружения и режим прогона: Адаптеры автотестов.

Вызовите installTracera() один раз в начале функции main или в flutter_test_config.dart. Используйте стандартные импорты flutter_test и integration_test — добавьте только installTracera, функции для скриншотов и вызовы tracera:

import 'package:flutter_test/flutter_test.dart';
import 'package:tracera/tracera.dart' as tracera;
import 'package:tracera_flutter/tracera_flutter.dart';

void main() {
  installTracera();

  testWidgets('user can sign in', (tester) async {
    await tracera.step('pump login', () async {
      await tester.pumpWidget(/* ... */);
    });
  }, tags: ['tracera-id-42']);
}

Привязка testCaseId и autotestName

Добавьте тег tracera-id-‹id› к testWidgets, test или group. Тег tracera-name-‹name› задаёт autotestName. В теге имени нельзя использовать пробелы; чтобы указать имя с пробелами, привяжите кейс внутри теста через tracera.testCase. Если тег имени не указан, то autotestName принимает значение имени теста во Flutter.

testWidgets('user can sign in', (tester) async {
  // ...
}, tags: ['tracera-id-42', 'tracera-name-e2e_sign_in']);

testWidgets('user can sign out', (tester) async {
  tracera.testCase(43, 'e2e/sign out');
});

Чтобы убрать предупреждения о неопределённых тегах, перечислите теги Tracera в разделе tags: файла dart_test.yaml.

Пропуск

Вызовите markTestSkipped('reason') внутри теста. Результат отправляется как Skipped, а причина добавляется в результат как comment.

testWidgets('checkout', (tester) async {
  markTestSkipped('needs a seeded account');
}, tags: ['tracera-id-42']);

Аргумент skip: у testWidgets или group в отчёт не попадает.

Шаги

Используйте tracera.step('…', () { … }). Колбэк setUp попадает в секцию результата Предусловие, тело теста — в Тест, колбэк tearDown — в Постусловие. Шаги внутри setUpAll / tearDownAll в отчёт не попадают.

setUp(() {
  tracera.step('open shop', () {});
});

testWidgets('checkout', (tester) async {
  tracera.testCase(10);

  await tracera.step('add item', () async {
    await tester.pumpWidget(/* ... */);
    tracera.step('nested leaf', () {});
  });
});

tearDown(() {
  tracera.step('close shop', () {});
});

Комментарии, ошибки и вложения

Лимиты и допустимые MIME-типы: Адаптеры автотестов.

tracera.comment, tracera.error и вложения добавляются к открытому шагу, а если шаг не открыт — к результату. tracera.attachmentFile принимает путь к файлу, tracera.attachmentBytes — имя и байты, а также необязательный mimeType. Вложения загружаются при отправке результата.

tracera.comment('result-level note');
tracera.error('result-level error');
tracera.attachmentFile('test/fixtures/screenshot.png');
tracera.step('open login', () {
  tracera.comment('step note');
  tracera.attachmentBytes(
    'body.json',
    utf8.encode('{"ok":true}'),
    mimeType: 'application/json',
  );
});

Скриншоты

Скриншоты добавляются как PNG-вложения — со снимка или из байтов, которые вы передаёте.

  • attachScreenshot(tester) снимает первый RepaintBoundary в виджет-тесте.
  • attachScreenshotBytes(bytes) добавляет готовые PNG-байты.
  • attachIntegrationScreenshot(name: 'checkout') делает скриншот устройства в integration_test.
testWidgets('checkout', (tester) async {
  await tester.pumpWidget(const RepaintBoundary(child: CheckoutPage()));
  await attachScreenshot(tester, fileName: 'checkout.png');
});

Параметризованные тесты

Создайте в цикле отдельный testWidgets для каждой строки. Если имя не указано, то autotestName принимает значение имени теста, поэтому дайте каждой строке уникальный заголовок. Чтобы задать имя для каждой строки, передайте его в tracera.testCase:

for (final login in ['alice', 'bob']) {
  testWidgets('sign in as $login', (tester) async {
    tracera.testCase(7, 'login as $login');
  });
}

Если тест перезапускается, в отчёт попадает только последняя попытка. На вкладке Env результата тогда появляется FLUTTER_RETRY (см. Адаптеры автотестов).