feat(app): add manual entry and sharing flows

This commit is contained in:
JiWoong Sul
2025-11-19 16:36:39 +09:00
parent 5ade584370
commit 947fe59486
110 changed files with 5937 additions and 3781 deletions

View File

@@ -14,7 +14,7 @@ void main() {
group('RestaurantProvider Tests', () {
late ProviderContainer container;
late MockRestaurantRepository mockRepository;
setUp(() {
mockRepository = MockRestaurantRepository();
container = ProviderContainer(
@@ -23,11 +23,11 @@ void main() {
],
);
});
tearDown(() {
container.dispose();
});
test('restaurantListProvider returns stream of restaurants', () async {
// Arrange
final restaurants = [
@@ -45,17 +45,18 @@ void main() {
updatedAt: DateTime.now(),
),
];
when(mockRepository.watchRestaurants())
.thenAnswer((_) => Stream.value(restaurants));
when(
mockRepository.watchRestaurants(),
).thenAnswer((_) => Stream.value(restaurants));
// Act
final result = container.read(restaurantListProvider);
// Assert
expect(result, isA<AsyncValue<List<Restaurant>>>());
});
test('searchRestaurantsProvider filters restaurants by query', () async {
// Arrange
final restaurants = [
@@ -86,30 +87,33 @@ void main() {
updatedAt: DateTime.now(),
),
];
when(mockRepository.searchRestaurants('김치'))
.thenAnswer((_) async => [restaurants[0]]);
when(
mockRepository.searchRestaurants('김치'),
).thenAnswer((_) async => [restaurants[0]]);
// Act
final result = await container.read(searchRestaurantsProvider('김치').future);
final result = await container.read(
searchRestaurantsProvider('김치').future,
);
// Assert
expect(result.length, 1);
expect(result.first.name, '김치찌개');
});
test('selectedCategoryProvider updates category filter', () {
// Act
container.read(selectedCategoryProvider.notifier).state = '한식';
// Assert
expect(container.read(selectedCategoryProvider), '한식');
});
test('restaurantNotifier adds new restaurant', () async {
// Arrange
when(mockRepository.addRestaurant(any)).thenAnswer((_) async {});
// Act
final notifier = container.read(restaurantNotifierProvider.notifier);
await notifier.addRestaurant(
@@ -122,11 +126,11 @@ void main() {
longitude: 127.0,
source: DataSource.USER_INPUT,
);
// Assert
verify(mockRepository.addRestaurant(any)).called(1);
});
test('restaurantNotifier updates existing restaurant', () async {
// Arrange
final restaurant = Restaurant(
@@ -142,107 +146,116 @@ void main() {
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
when(mockRepository.updateRestaurant(any)).thenAnswer((_) async {});
// Act
final notifier = container.read(restaurantNotifierProvider.notifier);
await notifier.updateRestaurant(restaurant);
// Assert
verify(mockRepository.updateRestaurant(any)).called(1);
});
test('restaurantNotifier deletes restaurant', () async {
// Arrange
when(mockRepository.deleteRestaurant('1')).thenAnswer((_) async {});
// Act
final notifier = container.read(restaurantNotifierProvider.notifier);
await notifier.deleteRestaurant('1');
// Assert
verify(mockRepository.deleteRestaurant('1')).called(1);
});
test('filteredRestaurantsProvider filters by search and category', () async {
// Arrange
final restaurants = [
Restaurant(
id: '1',
name: '김치찌개',
category: 'korean',
subCategory: '한식',
roadAddress: '서울시',
jibunAddress: '서울시',
latitude: 37.5,
longitude: 127.0,
source: DataSource.USER_INPUT,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
),
Restaurant(
id: '2',
name: '스시',
category: 'japanese',
subCategory: '일식',
roadAddress: '서울시',
jibunAddress: '서울시',
latitude: 37.5,
longitude: 127.0,
source: DataSource.USER_INPUT,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
),
];
when(mockRepository.watchRestaurants())
.thenAnswer((_) => Stream.value(restaurants));
// Act - 카테고리 필터 설정
container.read(selectedCategoryProvider.notifier).state = '한식';
// Assert
// filteredRestaurantsProvider는 StreamProvider이므로 실제 테스트에서는
// 비동기 처리가 필요함
});
test('restaurantsWithinDistanceProvider returns nearby restaurants', () async {
// Arrange
final nearbyRestaurants = [
Restaurant(
id: '1',
name: '가까운 맛집',
category: 'korean',
subCategory: '한식',
roadAddress: '서울시',
jibunAddress: '서울시',
latitude: 37.5665,
longitude: 126.9780,
source: DataSource.USER_INPUT,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
),
];
when(mockRepository.getRestaurantsWithinDistance(
userLatitude: 37.5665,
userLongitude: 126.9780,
maxDistanceInMeters: 1000,
)).thenAnswer((_) async => nearbyRestaurants);
// Act
final result = await container.read(
restaurantsWithinDistanceProvider((
latitude: 37.5665,
longitude: 126.9780,
maxDistance: 1000,
)).future,
);
// Assert
expect(result.length, 1);
expect(result.first.name, '가까운 맛집');
});
test(
'filteredRestaurantsProvider filters by search and category',
() async {
// Arrange
final restaurants = [
Restaurant(
id: '1',
name: '김치찌개',
category: 'korean',
subCategory: '한식',
roadAddress: '서울시',
jibunAddress: '서울시',
latitude: 37.5,
longitude: 127.0,
source: DataSource.USER_INPUT,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
),
Restaurant(
id: '2',
name: '스시',
category: 'japanese',
subCategory: '일식',
roadAddress: '서울시',
jibunAddress: '서울시',
latitude: 37.5,
longitude: 127.0,
source: DataSource.USER_INPUT,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
),
];
when(
mockRepository.watchRestaurants(),
).thenAnswer((_) => Stream.value(restaurants));
// Act - 카테고리 필터 설정
container.read(selectedCategoryProvider.notifier).state = '한식';
// Assert
// filteredRestaurantsProvider는 StreamProvider이므로 실제 테스트에서는
// 비동기 처리가 필요함
},
);
test(
'restaurantsWithinDistanceProvider returns nearby restaurants',
() async {
// Arrange
final nearbyRestaurants = [
Restaurant(
id: '1',
name: '가까운 맛집',
category: 'korean',
subCategory: '한식',
roadAddress: '서울시',
jibunAddress: '서울시',
latitude: 37.5665,
longitude: 126.9780,
source: DataSource.USER_INPUT,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
),
];
when(
mockRepository.getRestaurantsWithinDistance(
userLatitude: 37.5665,
userLongitude: 126.9780,
maxDistanceInMeters: 1000,
),
).thenAnswer((_) async => nearbyRestaurants);
// Act
final result = await container.read(
restaurantsWithinDistanceProvider((
latitude: 37.5665,
longitude: 126.9780,
maxDistance: 1000,
)).future,
);
// Assert
expect(result.length, 1);
expect(result.first.name, '가까운 맛집');
},
);
});
}
}