test(client): 新增设备侧集成测试(真机跑通后端可达性)

红线第 10 条(设备验证必须设备侧取证)配套:integration_test/app_backend_test.dart
在手机进程里真实请求 /app/home/feed 与 /app/dramas/{id},并用真 App 断言首页剧目列表能渲染。
把 API_BASE_URL 打进设备日志,便于区分地址不对与设备连不上。

注意:真机执行由用户负责(用户 20:45 指令),本文件按原样交付、不再改动。
本项目 iOS 用 SPM,无 Podfile,不需要 pod install。
This commit is contained in:
Vicky committed 2026-10-16 18:05:58 +08:00
1 parent d7eff4ca59
commit 84a1f58a0a
3 files changed
+118

No files matched your search

+74
View File
@@ -0,0 +1,74 @@
// Author: fruit.com.cn
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fruitshorts/app.dart';
import 'package:fruitshorts/core/config/app_config.dart';
import 'package:fruitshorts/core/data/remote/api_client.dart';
import 'package:fruitshorts/core/data/remote/catalog_api.dart';
import 'package:integration_test/integration_test.dart';
/// 设备侧集成测试:**在手机进程里**真实请求开发机上的 app-api。
///
/// 跑法(红线第 10 条要求的"设备侧取证"):
/// ```
/// IP=$(ipconfig getifaddr en0)
/// flutter test integration_test -d <device-id> --dart-define=API_BASE_URL=http://$IP:8081
/// ```
/// 断言失败时会把实际使用的地址一起打出来,便于区分"地址不对"还是"设备连不上"。
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
final baseUrl = AppConfig.apiBaseUrl;
testWidgets('should_fetch_home_feed_and_drama_detail_when_device_reaches_backend', (
tester,
) async {
debugPrint('[device] API_BASE_URL=$baseUrl');
final client = ApiClient(baseUrl: baseUrl);
addTearDown(client.close);
final api = CatalogApi(client);
final feed = await api.homeFeed();
expect(
feed.dramas,
isNotEmpty,
reason: '设备侧拿不到首页列表(API_BASE_URL=$baseUrl)',
);
debugPrint('[device] 首页分区=${feed.sections.length} 剧目=${feed.dramas.length}');
final card = feed.dramas.first;
expect(card.id, isNotEmpty, reason: '设备侧首页卡片 id 为空');
final detail = await api.dramaDetail(card.id);
expect(detail.id, card.id, reason: '详情返回的 id 与卡片不一致');
expect(
detail.episodes,
isNotEmpty,
reason: '设备侧拿到的详情没有剧集(dramaId=${card.id})',
);
debugPrint('[device] 详情 id=${detail.id} 剧集=${detail.episodes.length}');
});
testWidgets('should_render_home_drama_list_when_app_boots_on_device', (
tester,
) async {
// 用真 App(真网络、真目录控制器):首页底部标签栏出现即代表"剧目列表加载成功",
// 也就是用户在真机上遇到的那个「剧目列表加载失败」已经消失。
await tester.pumpWidget(const LumaDramaApp());
var loaded = false;
for (var attempt = 0; attempt < 60 && !loaded; attempt++) {
await tester.pump(const Duration(milliseconds: 500));
loaded = find.byKey(const Key('home-tabs-bar')).evaluate().isNotEmpty;
}
expect(
loaded,
isTrue,
reason: '首页 30 秒内没渲染出剧目列表(API_BASE_URL=$baseUrl)',
);
debugPrint('[device] 首页剧目列表已渲染:API_BASE_URL=$baseUrl');
});
}
+39
View File
@@ -134,6 +134,11 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_driver:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
flutter_launcher_icons:
dependency: "direct dev"
description:
@@ -165,6 +170,11 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
html:
dependency: transitive
description:
@@ -189,6 +199,11 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.12.0"
integration_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
intl:
dependency: transitive
description:
@@ -333,6 +348,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.5.2"
process:
dependency: transitive
description:
name: process
sha256: "4242ba3508d37e01808bdf71ad1d5bb93a8d671bf2e7450e6b1b353fb0808891"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.0.6"
provider:
dependency: "direct main"
description:
@@ -434,6 +457,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.4.1"
sync_http:
dependency: transitive
description:
name: sync_http
sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.3.1"
term_glyph:
dependency: transitive
description:
@@ -522,6 +553,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.1"
webdriver:
dependency: transitive
description:
name: webdriver
sha256: "28b82ec894fed45dd71c23ba62d1af973ed97dd59a4f5790a4d38b0b13e5657e"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.2.0"
xdg_directories:
dependency: transitive
description:
+5
View File
@@ -46,6 +46,11 @@ dev_dependencies:
flutter_test:
sdk: flutter
# 设备侧集成测试:真机/模拟器进程里真实发请求,验证"设备能不能连到开发机后端"
# (红线第 10 条:设备验证必须设备侧取证,不能用开发机 curl 充数)
integration_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your