158 lines
4.5 KiB
Dart
158 lines
4.5 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:mocktail/mocktail.dart';
|
|
import 'package:kooltab2/models/product.dart';
|
|
import 'package:kooltab2/services/product_service.dart';
|
|
import 'package:kooltab2/viewmodels/inventory_view_model.dart';
|
|
|
|
class MockProductService extends Mock implements ProductService {}
|
|
|
|
void main() {
|
|
late InventoryViewModel viewModel;
|
|
late MockProductService mockService;
|
|
|
|
setUp(() {
|
|
mockService = MockProductService();
|
|
viewModel = InventoryViewModel(productService: mockService);
|
|
});
|
|
|
|
setUpAll(() {
|
|
registerFallbackValue(const Product(
|
|
id: 'fallback',
|
|
name: 'Fallback',
|
|
category: 'Test',
|
|
stockQuantity: 0,
|
|
lowStockThreshold: 0,
|
|
priceInCents: 0,
|
|
));
|
|
});
|
|
|
|
final testProducts = [
|
|
const Product(
|
|
id: 'prod-1',
|
|
name: 'Beer',
|
|
category: 'Drinks',
|
|
stockQuantity: 20,
|
|
lowStockThreshold: 5,
|
|
priceInCents: 400,
|
|
),
|
|
const Product(
|
|
id: 'prod-2',
|
|
name: 'Wine',
|
|
category: 'Drinks',
|
|
stockQuantity: 3,
|
|
lowStockThreshold: 5,
|
|
priceInCents: 600,
|
|
),
|
|
];
|
|
|
|
group('InventoryViewModel', () {
|
|
group('load', () {
|
|
test('loads products from service', () async {
|
|
when(() => mockService.getProducts())
|
|
.thenAnswer((_) async => testProducts);
|
|
|
|
await viewModel.load();
|
|
|
|
expect(viewModel.products, testProducts);
|
|
verify(() => mockService.getProducts()).called(1);
|
|
});
|
|
|
|
test('notifies listeners after load', () async {
|
|
var notifyCount = 0;
|
|
viewModel.addListener(() => notifyCount++);
|
|
when(() => mockService.getProducts())
|
|
.thenAnswer((_) async => testProducts);
|
|
|
|
await viewModel.load();
|
|
|
|
expect(notifyCount, 1);
|
|
});
|
|
});
|
|
|
|
group('decreaseStock', () {
|
|
test('decreases stock via service', () async {
|
|
when(() => mockService.decreaseStock('prod-1', 3))
|
|
.thenAnswer((_) async {});
|
|
|
|
await viewModel.decreaseStock('prod-1', 3);
|
|
|
|
verify(() => mockService.decreaseStock('prod-1', 3)).called(1);
|
|
});
|
|
|
|
test('updates local product cache', () async {
|
|
when(() => mockService.getProducts())
|
|
.thenAnswer((_) async => testProducts);
|
|
when(() => mockService.decreaseStock('prod-1', 5))
|
|
.thenAnswer((_) async {});
|
|
|
|
await viewModel.load();
|
|
await viewModel.decreaseStock('prod-1', 5);
|
|
|
|
final product = viewModel.products.firstWhere((p) => p.id == 'prod-1');
|
|
expect(product.stockQuantity, 15);
|
|
});
|
|
|
|
test('notifies listeners after decrease', () async {
|
|
var notifyCount = 0;
|
|
viewModel.addListener(() => notifyCount++);
|
|
when(() => mockService.decreaseStock('prod-1', 1))
|
|
.thenAnswer((_) async {});
|
|
|
|
await viewModel.decreaseStock('prod-1', 1);
|
|
|
|
expect(notifyCount, 1);
|
|
});
|
|
});
|
|
|
|
group('increaseStock', () {
|
|
test('increases stock via service', () async {
|
|
when(() => mockService.increaseStock('prod-1', 5))
|
|
.thenAnswer((_) async {});
|
|
|
|
await viewModel.increaseStock('prod-1', 5);
|
|
|
|
verify(() => mockService.increaseStock('prod-1', 5)).called(1);
|
|
});
|
|
|
|
test('updates local product cache', () async {
|
|
when(() => mockService.getProducts())
|
|
.thenAnswer((_) async => testProducts);
|
|
when(() => mockService.increaseStock('prod-2', 2))
|
|
.thenAnswer((_) async {});
|
|
|
|
await viewModel.load();
|
|
await viewModel.increaseStock('prod-2', 2);
|
|
|
|
final product = viewModel.products.firstWhere((p) => p.id == 'prod-2');
|
|
expect(product.stockQuantity, 5);
|
|
});
|
|
|
|
test('notifies listeners after increase', () async {
|
|
var notifyCount = 0;
|
|
viewModel.addListener(() => notifyCount++);
|
|
when(() => mockService.increaseStock('prod-1', 1))
|
|
.thenAnswer((_) async {});
|
|
|
|
await viewModel.increaseStock('prod-1', 1);
|
|
|
|
expect(notifyCount, 1);
|
|
});
|
|
});
|
|
|
|
group('edge cases', () {
|
|
test('handles decrease for product not in local cache', () async {
|
|
when(() => mockService.getProducts())
|
|
.thenAnswer((_) async => testProducts);
|
|
when(() => mockService.decreaseStock('unknown', 1))
|
|
.thenAnswer((_) async {});
|
|
|
|
await viewModel.load();
|
|
await viewModel.decreaseStock('unknown', 1);
|
|
|
|
verify(() => mockService.decreaseStock('unknown', 1)).called(1);
|
|
expect(viewModel.products.length, 2);
|
|
});
|
|
});
|
|
});
|
|
}
|