feat: add tests
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user