import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:jiu_client/core/api/api_client.dart'; import 'package:jiu_client/core/auth/auth_state.dart'; import 'package:jiu_client/core/theme/themes.dart'; import 'package:jiu_client/models/product_option.dart'; import 'package:jiu_client/models/stock_in.dart'; import 'package:jiu_client/models/warehouse.dart'; import 'package:jiu_client/providers/stock_in_provider.dart'; import 'package:jiu_client/providers/warehouse_provider.dart'; import 'package:jiu_client/providers/product_option_provider.dart'; import 'package:jiu_client/repositories/stock_in_repository.dart'; import 'package:jiu_client/screens/stock_in/stock_in_form_screen.dart'; import 'package:jiu_client/widgets/ds/grid_combo_cell.dart'; class _FakeWarehouses extends WarehouseListNotifier { @override Future> build() async => const [Warehouse(id: 1, name: '主仓', isDefault: true)]; } /// 可配置仓库列表的假 notifier(T5 默认仓填充回归用)。 class _ConfigurableWarehouses extends WarehouseListNotifier { final List _list; _ConfigurableWarehouses(this._list); @override Future> build() async => _list; } /// 编辑模式假仓库:get() 返回固定单据(供 _loadEditOrder 消费)。 class _FakeStockInRepoForEdit extends StockInRepository { final StockInOrder order; _FakeStockInRepoForEdit(this.order) : super(ApiClient(token: 't')); @override Future get(int id) async => order; } class _FakeNames extends ProductNameListNotifier { @override Future> build() async => const [ ProductNameOption(id: 10, name: '茅台飞天', code: 'P001'), ProductNameOption(id: 11, name: '五粮液', code: 'P002'), ]; } class _FakeSeries extends ProductSeriesListNotifier { @override Future> build() async => const [ ProductSeriesOption(id: 20, name: '53度'), ]; } class _FakeSpecs extends ProductSpecListNotifier { @override Future> build() async => const [ ProductSpecOption(id: 30, name: '500ml'), ]; } void main() { TestWidgetsFlutterBinding.ensureInitialized(); SharedPreferences.setMockInitialValues({}); testWidgets('stock-in form: picking 商品名称 fills the cell', (tester) async { tester.view.physicalSize = const Size(1400, 1000); tester.view.devicePixelRatio = 1.0; addTearDown(tester.view.resetPhysicalSize); await tester.pumpWidget(ProviderScope( overrides: [ warehouseListProvider.overrideWith(() => _FakeWarehouses()), productNameListProvider.overrideWith(() => _FakeNames()), productSeriesListProvider.overrideWith(() => _FakeSeries()), productSpecListProvider.overrideWith(() => _FakeSpecs()), isReadonlyProvider.overrideWithValue(false), ], child: MaterialApp( theme: buildTheme('a'), home: const Scaffold(body: StockInFormScreen()), ), )); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); // Tap the 商品名称 cell to focus/open its popup. final nameCell = find.text('选择商品名称'); expect(nameCell, findsWidgets); await tester.tap(nameCell.first); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); // The option list should appear. expect(find.text('五粮液'), findsWidgets, reason: 'popup list should show options'); // Tap the option. await tester.tap(find.text('五粮液').last); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); // After picking, the cell should display 五粮液 and the hint should be gone. expect(find.text('五粮液'), findsOneWidget, reason: 'cell should show the picked name'); expect(find.text('选择商品名称'), findsNothing, reason: 'hint should be replaced by the picked name'); }); // ── T5:新建入库单默认填充默认仓库(2026-07-14)────────────────────── // // _initWarehouseDefault 语义:仓库列表加载完成后, // isDefault 的仓 优先;无默认时仅剩 1 个仓才取它;否则保持未选(null)。 // 编辑模式不受影响(_loadEditOrder 已从单据自身仓库回填)。 int? _warehouseSelectedId(WidgetTester tester) => tester .widgetList(find.byType(GridComboCell)) .firstWhere((c) => c.hint == '选择仓库…') .selectedId; Future _pumpForm(WidgetTester tester, List overrides, {int? editOrderId}) async { tester.view.physicalSize = const Size(1400, 1000); tester.view.devicePixelRatio = 1.0; addTearDown(tester.view.resetPhysicalSize); await tester.pumpWidget(ProviderScope( overrides: overrides, child: MaterialApp( theme: buildTheme('a'), home: Scaffold(body: StockInFormScreen(editOrderId: editOrderId)), ), )); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); // _initWarehouseDefault / _loadEditOrder 都是异步(await provider.future), // 多 pump 几拍确保 setState 落地。 await tester.pump(const Duration(milliseconds: 100)); } testWidgets('新建入库单:有默认仓(isDefault=true)时自动选中默认仓', (tester) async { await _pumpForm(tester, [ warehouseListProvider.overrideWith(() => _FakeWarehouses()), // 主仓 isDefault productNameListProvider.overrideWith(() => _FakeNames()), productSeriesListProvider.overrideWith(() => _FakeSeries()), productSpecListProvider.overrideWith(() => _FakeSpecs()), isReadonlyProvider.overrideWithValue(false), ]); expect(_warehouseSelectedId(tester), 1); }); testWidgets('新建入库单:无默认仓且多仓时保持未选', (tester) async { await _pumpForm(tester, [ warehouseListProvider.overrideWith(() => _ConfigurableWarehouses(const [ Warehouse(id: 1, name: '主仓', isDefault: false), Warehouse(id: 2, name: '分仓', isDefault: false), ])), productNameListProvider.overrideWith(() => _FakeNames()), productSeriesListProvider.overrideWith(() => _FakeSeries()), productSpecListProvider.overrideWith(() => _FakeSpecs()), isReadonlyProvider.overrideWithValue(false), ]); expect(_warehouseSelectedId(tester), isNull); }); testWidgets('新建入库单:无默认仓但仅有 1 个仓时自动选中该仓', (tester) async { await _pumpForm(tester, [ warehouseListProvider.overrideWith(() => _ConfigurableWarehouses(const [ Warehouse(id: 7, name: '唯一仓', isDefault: false), ])), productNameListProvider.overrideWith(() => _FakeNames()), productSeriesListProvider.overrideWith(() => _FakeSeries()), productSpecListProvider.overrideWith(() => _FakeSpecs()), isReadonlyProvider.overrideWithValue(false), ]); expect(_warehouseSelectedId(tester), 7); }); testWidgets('编辑模式:不被默认仓覆盖,仍显示单据原仓库', (tester) async { const order = StockInOrder( id: 99, orderNo: 'SI2024010099', warehouseId: 2, // 单据原仓库 = 分仓(非默认仓) status: 'draft', items: [], ); await _pumpForm( tester, [ // 主仓(id=1)isDefault=true,若默认仓填充逻辑误在编辑模式生效会把它选中, // 但单据自身仓库是 id=2,回归断言二者不一致时以单据为准。 warehouseListProvider.overrideWith(() => _ConfigurableWarehouses(const [ Warehouse(id: 1, name: '主仓', isDefault: true), Warehouse(id: 2, name: '分仓', isDefault: false), ])), stockInRepositoryProvider .overrideWithValue(_FakeStockInRepoForEdit(order)), productNameListProvider.overrideWith(() => _FakeNames()), productSeriesListProvider.overrideWith(() => _FakeSeries()), productSpecListProvider.overrideWith(() => _FakeSpecs()), isReadonlyProvider.overrideWithValue(false), ], editOrderId: 99, ); expect(_warehouseSelectedId(tester), 2); }); }