import 'package:apskel_pos_flutter_v2/application/checkout/checkout_form/checkout_form_bloc.dart'; import 'package:apskel_pos_flutter_v2/common/types/sell_by.dart'; import 'package:apskel_pos_flutter_v2/domain/order/order.dart'; import 'package:apskel_pos_flutter_v2/domain/product/product.dart'; import 'package:flutter_test/flutter_test.dart'; /// Ikan Tude — Rp 4.500 per ons. final ikanTude = Product.empty().copyWith( id: 'ikan-tude', name: 'Ikan Tude', price: 4500, isActive: true, sellBy: SellBy.weight, unitId: 'unit-ons', unitName: 'Ons', unitAbbreviation: 'ons', ); final nasiGoreng = Product.empty().copyWith( id: 'nasi-goreng', name: 'Nasi Goreng', price: 25000, isActive: true, ); void main() { group('keranjang produk timbangan', () { test('dua penimbangan produk yang sama menjadi dua baris', () async { final bloc = CheckoutFormBloc(); bloc.add(CheckoutFormEvent.addWeightedItem(ikanTude, null, 4.2)); bloc.add(CheckoutFormEvent.addWeightedItem(ikanTude, null, 5.6)); await bloc.stream.firstWhere((s) => s.items.length == 2); final items = bloc.state.items; expect(items.length, 2); expect(items.map((e) => e.weight), [4.2, 5.6]); expect(items.every((e) => e.quantity == 1), isTrue); expect(items[0].lineId, isNot(items[1].lineId)); }); test('produk cacah tetap digabung jadi satu baris', () async { final bloc = CheckoutFormBloc(); bloc.add(CheckoutFormEvent.addItem(nasiGoreng, null)); bloc.add(CheckoutFormEvent.addItem(nasiGoreng, null)); await bloc.stream.firstWhere((s) => s.items.isNotEmpty && s.items.first.quantity == 2); expect(bloc.state.items.length, 1); expect(bloc.state.items.first.quantity, 2); }); test('produk timbangan tidak bisa masuk tanpa berat', () async { final bloc = CheckoutFormBloc(); bloc.add(CheckoutFormEvent.addItem(ikanTude, null)); await Future.delayed(Duration.zero); expect(bloc.state.items, isEmpty); }); test('total baris dihitung berat x harga satuan', () { final line = ProductQuantity( product: ikanTude, quantity: 1, notes: '', weight: 4.2, ); expect(line.lineTotal, closeTo(18900, 0.001)); expect(line.quantityLabel, '4,2 ons'); }); test('total keranjang mencampur baris berbobot dan baris cacah', () { final items = [ ProductQuantity( product: ikanTude, quantity: 1, notes: '', weight: 4.2, ), ProductQuantity(product: nasiGoreng, quantity: 2, notes: ''), ]; expect(items.cartTotal, closeTo(18900 + 50000, 0.001)); expect(items.cartItemCount, 3); }); }); group('permintaan ke backend', () { test('baris berbobot dikirim quantity 1 dan membawa berat', () { final request = OrderItemRequest.fromProductQuantity( ProductQuantity( product: ikanTude, quantity: 1, notes: '', weight: 4.2, ), ); expect(request.quantity, 1); expect(request.weight, 4.2); expect(request.unitPrice, 4500); }); test('produk cacah tidak membawa berat sama sekali', () { final request = OrderItemRequest.fromProductQuantity( ProductQuantity(product: nasiGoreng, quantity: 2, notes: ''), ); expect(request.quantity, 2); expect(request.weight, isNull); }); }); group('tampilan baris pesanan', () { test('baris berbobot memakai berat, bukan quantity', () { final item = OrderItem.empty().copyWith( quantity: 1, unitPrice: 4500, totalPrice: 18900, weight: 4.2, unitAbbreviation: 'ons', ); expect(item.isWeighted, isTrue); expect(item.quantityLabel, '4,2 ons'); expect(item.quantityPriceLabel, '4,2 ons x Rp 4.500'); }); test('baris biasa tetap memakai quantity', () { final item = OrderItem.empty().copyWith(quantity: 2, unitPrice: 25000); expect(item.isWeighted, isFalse); expect(item.quantityLabel, '2'); expect(item.quantityPriceLabel, '2 x Rp 25.000'); }); }); }