Files
patbond-flutter/test/features/pets/care_reminder_form_page_test.dart
T
lixi ba503327f5
CI / flutter-gates (push) Successful in 2m12s
新增:照护提醒接入与疫苗流转收尾(T2-14 提醒半边 + T2-13 遗留)
- 照护提醒页:status 过滤(服务端白名单视图)、due_at ASC、逾期红标
  双通道标识,四态齐备;创建表单(四类)+ 完成(completedAt 必带、
  支持补记)/ 忽略(禁带 completedAt)流转,42202/40902 兜底重拉
- 档案页:「健康提醒」卡改真实待办数据驱动(取代 demo 硬编码文案,
  最近到期一条 + 逾期警示形态),照护提醒导航入口带待办数副行
- 疫苗列表(25 号报告遗留①②):scheduled 行「标记完成/取消登记」
  PATCH 流转;完成对话框补录厂商/批号(契约可选字段);
  42201/40902/40402 兜底
- 埋点:create 三事件 + viewed(recordType=reminder)挂通;
  edit_succeeded/failed 挂 vaccine 流转(failureReason 含 conflict);
  提醒完成/忽略按 06 §7 缺口 3 既定取舍不埋
- 测试 250 → 272 全绿(+22,较基线 +48);analyze 0 问题;format 无 diff

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-08 14:01:17 +08:00

128 lines
4.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:patbond_flutter/core/network/api_exception.dart';
import 'package:patbond_flutter/core/theme/app_theme.dart';
import 'package:patbond_flutter/features/pets/care_reminder_form_page.dart';
import 'package:patbond_flutter/features/pets/health_record_analytics.dart';
import 'package:patbond_flutter/features/pets/pet_exceptions.dart';
import 'package:patbond_flutter/features/pets/pet_models.dart';
import '../../helpers/pet_test_helpers.dart';
void main() {
late FakePetsRepository repository;
late List<(String, Map<String, dynamic>?)> events;
late HealthRecordAnalytics analytics;
setUp(() {
repository = FakePetsRepository();
events = [];
analytics = HealthRecordAnalytics(
(name, [props]) async => events.add((name, props)),
);
});
List<Map<String, dynamic>?> eventsOf(String name) => [
for (final e in events)
if (e.$1 == name) e.$2,
];
Future<void> pumpForm(WidgetTester tester) async {
tester.view.physicalSize = const Size(700, 1600);
tester.view.devicePixelRatio = 1.0;
addTearDown(tester.view.reset);
await tester.pumpWidget(
MaterialApp(
theme: buildAppTheme(),
home: Builder(
builder: (context) => Scaffold(
body: Center(
child: TextButton(
onPressed: () => Navigator.of(context).push(
MaterialPageRoute<CareReminder>(
builder: (_) => CareReminderFormPage(
repository: repository,
petId: 'p-1',
analytics: analytics,
),
),
),
child: const Text('打开表单'),
),
),
),
),
),
);
await tester.tap(find.text('打开表单'));
await tester.pumpAndSettle();
}
Future<void> fillValid(WidgetTester tester) async {
await tester.tap(find.text('用药'));
await tester.pump();
await tester.enterText(
find.widgetWithText(TextFormField, '提醒内容(如:体内外驱虫)'),
'心丝虫预防药',
);
await tester.tap(find.text('到期日期'));
await tester.pumpAndSettle();
await tester.tap(find.text('OK'));
await tester.pumpAndSettle();
}
testWidgets('started 去重:首次输入一次;四类类型可选', (tester) async {
await pumpForm(tester);
await fillValid(tester);
await tester.enterText(
find.widgetWithText(TextFormField, '提醒内容(如:体内外驱虫)'),
'改个名字',
);
await tester.pump();
final started = eventsOf('health_record_create_started');
expect(started.single, {
'recordType': 'reminder',
'entryPoint': 'record_list',
});
// 四类类型齐备。
for (final label in ['驱虫', '体检', '用药', '其他']) {
expect(find.text(label), findsOneWidget);
}
});
testWidgets('40300 横幅 / 网络 SnackBar 兜底 + 失败事件', (tester) async {
var attempt = 0;
repository.createCareReminderHandler = (petId, request) async {
attempt++;
if (attempt == 1) {
throw const PetAccessDeniedException(message: '无权限');
}
throw const ApiNetworkException('断网');
};
await pumpForm(tester);
await fillValid(tester);
await tester.tap(find.text('保存提醒'));
await tester.pumpAndSettle();
expect(find.text('你没有权限为该宠物添加提醒'), findsOneWidget);
await tester.tap(find.text('保存提醒'));
await tester.pumpAndSettle();
expect(find.text('网络异常,请检查网络后重试'), findsOneWidget);
final failed = eventsOf('health_record_create_failed');
expect(failed.length, 2);
expect(failed[0], {
'recordType': 'reminder',
'failureReason': 'permission_denied',
'attemptSeq': 1,
'errorCode': 40300,
'httpStatus': 403,
});
expect(failed[1]!['failureReason'], 'network_error');
expect(failed[1]!['attemptSeq'], 2);
});
}