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.

Skip

استدعِ 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 في اختبار widget.
  • 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 (انظر محوّلات الاختبار الآلي).