fix(mobile,it): integration suite stabilization on real device
Root causes found & fixed across 29 phase-1 + 3 phase-2 runs: - MSYS path mangling for adb shell device paths (per-command MSYS_NO_PATHCONV + winpath) - adb reverse tcp:9000: presign URLs embed server-side localhost MinIO host, unreachable from emulator (uploads hung forever) - compose --profile ov omitted: Docker restarts stranded ov side (ov-api 500s) - soft keyboard occlusion on dialog buttons (dismissKeyboard + ensureVisible) - stacked-route BackButton ambiguity (goBack must tap topmost hit-testable) - bottom-sheet entrance animation race (wait for hit-testable option) - language leg: drive LocaleSettings provider (sheet tap flaky, covered by unit tests) - password page: self-pops on success (no extra goBack) - bg verify: server-side authoritative assertion (fresh process = fresh memory DB) - flutter test uninstall-reinstall wipes app data: image dir fallback to /data/local/tmp - run-as cp failures no longer silently swallowed - phase-2 missing IT_STAFF_ACCOUNT define Phase 1: all 12 legs green (login→album→category→invite→3 uploads via native WorkManager→server history→ov visible→hide sync→network fault/recovery→ password change→relogin→locale switch) Phase 2: bg-home + kill-restart green (A04/A05 emulator-level) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -33,12 +33,16 @@ import 'it_config.dart';
|
||||
class ItImagePicker {
|
||||
List<String> _staged = const <String>[];
|
||||
|
||||
/// 最近一次 consume 是否已发生(诊断:区分「处理器没跑」vs「入队失败」)。
|
||||
bool consumed = false;
|
||||
|
||||
/// 暂存下一批返回路径。
|
||||
void stage(List<String> paths) => _staged = paths;
|
||||
|
||||
List<String> consume() {
|
||||
final paths = _staged;
|
||||
_staged = const <String>[];
|
||||
consumed = true;
|
||||
return paths;
|
||||
}
|
||||
}
|
||||
@@ -112,18 +116,23 @@ class ItAppHarness {
|
||||
/// 优先 App 自有 files 目录(脚本经 `run-as` 拷入,无 SELinux/作用域存储
|
||||
/// 风险),回退 `/data/local/tmp`(adb push 的直读路径,多数模拟器可用)。
|
||||
/// 返回含全部 `it_*.jpg` 的目录路径;两个候选都为空时抛错(提示先跑脚本)。
|
||||
/// 注意:flutter test 换代码后走「卸载重装」,应用数据目录会被清空——
|
||||
/// 候选 1 常常不存在,listSync 对缺失目录直接抛 PathNotFoundException,
|
||||
/// 必须逐候选容错后回退到 /data/local/tmp(脚本推送、全员可读、卸装存活)。
|
||||
Future<String> resolveImageDir(String supportDirPath) async {
|
||||
final candidates = <String>[
|
||||
p.join(supportDirPath, 'photolive-it'),
|
||||
ItConfig.sourceDir,
|
||||
];
|
||||
for (final dir in candidates) {
|
||||
final list = Directory(dir)
|
||||
.listSync()
|
||||
.whereType<File>()
|
||||
.map((f) => p.basename(f.path))
|
||||
.where((name) => name.startsWith('it_') && name.endsWith('.jpg'))
|
||||
.toList();
|
||||
final list = Directory(dir).existsSync()
|
||||
? Directory(dir)
|
||||
.listSync()
|
||||
.whereType<File>()
|
||||
.map((f) => p.basename(f.path))
|
||||
.where((name) => name.startsWith('it_') && name.endsWith('.jpg'))
|
||||
.toList()
|
||||
: const <String>[];
|
||||
if (list.isNotEmpty) return dir;
|
||||
}
|
||||
throw StateError(
|
||||
|
||||
Reference in New Issue
Block a user