fix(golden): 冻结应用时钟消除时间依赖非确定性(product_detail/license/inventory_check)
golden 失败根因:商品详情屏用实时 DateTime.now() 算「近30天出库」,随真实时间推移 6月流水掉出30天窗口→渲染变化→对不上。license/inventory_check 同理(剩余天数/盘点日期)。 修复: - product_detail_screen: DateTime.now() → appNow()(可注入时钟) - golden_harness: 所有 golden 渲染前冻结 appClock=2026-07-01 + tearDown 复位(ds-flow 钉死动态值) - 重录 license_mobile / m_inventory_check 6 张 golden;product_detail 冻结后自动匹配无需改图 本地 flutter test test/golden/ 全 120 通过。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
@@ -1,5 +1,6 @@
|
||||
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
||||
import '../../core/utils/dialog_util.dart';
|
||||
import '../../core/utils/clock.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@@ -395,7 +396,7 @@ class _ProductDetailScreenState extends ConsumerState<ProductDetailScreen> {
|
||||
final currentStock = _invRows.fold<num>(0, (s, i) => s + i.quantity);
|
||||
final cost = p.purchasePrice ?? 0;
|
||||
final stockValue = currentStock * cost;
|
||||
final now = DateTime.now();
|
||||
final now = appNow();
|
||||
final out30 = _logs.where((l) {
|
||||
if (l.direction != 'out') return false;
|
||||
final d = DateTime.tryParse(l.createdAt ?? '');
|
||||
|
||||
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 64 KiB |
@@ -3,6 +3,7 @@ import 'package:flutter/services.dart' show rootBundle, FontLoader;
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:jiu_client/core/theme/themes.dart';
|
||||
import 'package:jiu_client/core/utils/clock.dart';
|
||||
|
||||
// 加载真实中文字体(消除 golden 豆腐块),使 golden 能与原型截图做保真 diff。
|
||||
// 原型截图侧同样注入 Noto Sans SC(见 tools/fidelity.mjs),两边字体一致。
|
||||
@@ -67,6 +68,11 @@ Future<void> pumpGolden(
|
||||
double dpr = 2.0,
|
||||
}) async {
|
||||
await ensureGoldenFonts();
|
||||
// 冻结应用时钟:凡走 appNow() 的展示计算(如商品详情「近30天出库」)不再依赖真实时间,
|
||||
// 保证 golden 确定性(ds-flow:golden 钉死一切动态值)。选 2026-07-01,使 fake 6 月流水
|
||||
// 稳定落在「近30天」窗口内。tearDown 复位,不影响其它测试。
|
||||
appClock = () => DateTime(2026, 7, 1, 12, 0);
|
||||
addTearDown(() => appClock = () => DateTime.now());
|
||||
tester.view.physicalSize = Size(logical.width * dpr, logical.height * dpr);
|
||||
tester.view.devicePixelRatio = dpr;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
|
||||