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

@@ -1,44 +1,43 @@
@Skip('Integration-heavy parser tests are temporarily disabled')
import 'package:flutter_test/flutter_test.dart';
import 'package:lunchpick/data/datasources/remote/naver_map_parser.dart';
import 'package:lunchpick/data/api/naver_api_client.dart';
import 'package:dio/dio.dart';
import 'package:lunchpick/core/errors/network_exceptions.dart';
import 'package:lunchpick/data/api/naver/naver_local_search_api.dart';
import '../../../../mocks/mock_naver_api_client.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('NaverMapParser V2 테스트 - 새로운 파싱 흐름', () {
late NaverMapParser parser;
late MockNaverApiClient mockApiClient;
setUp(() {
mockApiClient = MockNaverApiClient();
parser = NaverMapParser(apiClient: mockApiClient);
});
test('새로운 흐름: 단축 URL → 2차 리디렉션 → HTML → 두 번째 한글 추출', () async {
// Given
const url = 'https://naver.me/xtest1234';
const finalUrl = 'https://map.naver.com/p/restaurant/1234567890';
const placeId = '1234567890';
const placeName = '스타벅스 시청점'; // 두 번째 한글로 추출될 값
const placeName = '스타벅스 시청점'; // 두 번째 한글로 추출될 값
// 단축 URL 리디렉션 설정
mockApiClient.setUrlRedirect(url, finalUrl);
// 테스트용 메서드 추가 (실제로는 NaverApiClient에 구현)
mockApiClient.setFinalRedirectUrl(
'https://map.naver.com/p/entry/place/$placeId',
'https://pcmap.place.naver.com/place/$placeId/home'
'https://pcmap.place.naver.com/place/$placeId/home',
);
mockApiClient.setSecondKoreanText(
'https://pcmap.place.naver.com/place/$placeId/home',
placeName
placeName,
);
// 검색 결과 설정
final searchResults = [
NaverLocalSearchResult(
@@ -53,37 +52,37 @@ void main() {
mapy: 375666805,
),
];
mockApiClient.setSearchResults(placeName, searchResults);
// When
final result = await parser.parseRestaurantFromUrl(url);
// Then
expect(result.name, placeName);
expect(result.naverPlaceId, placeId);
});
test('429 에러 발생 시 RateLimitException 발생', () async {
// Given
const url = 'https://naver.me/xtest1234';
const finalUrl = 'https://map.naver.com/p/restaurant/1234567890';
// 단축 URL 리디렉션은 성공
mockApiClient.setUrlRedirect(url, finalUrl);
// 429 에러 시뮬레이션
mockApiClient.shouldThrowError = true;
mockApiClient.errorMessage = '429 Too Many Requests';
mockApiClient.setThrow429Error();
// When & Then
expect(
() => parser.parseRestaurantFromUrl(url),
throwsA(isA<RateLimitException>()),
);
});
test('HTML에서 두 번째 한글 텍스트 추출 테스트', () async {
// Given
const html = '''
@@ -96,46 +95,46 @@ void main() {
</body>
</html>
''';
// NaverApiClient의 private 메서드를 직접 테스트할 수 없으므로
// 전체 흐름으로 테스트
const placeId = '1234567890';
mockApiClient.setHtmlResponse(
'https://pcmap.place.naver.com/place/$placeId/home',
html
html,
);
// extractSecondKoreanText 메서드 결과 설정
mockApiClient.setSecondKoreanText(
'https://pcmap.place.naver.com/place/$placeId/home',
'카페 칼리스타 구로본점' // 메뉴 다음의 두 번째 한글
'카페 칼리스타 구로본점', // 메뉴 다음의 두 번째 한글
);
// When
final result = await mockApiClient.extractSecondKoreanText(
'https://pcmap.place.naver.com/place/$placeId/home'
'https://pcmap.place.naver.com/place/$placeId/home',
);
// Then
expect(result, '카페 칼리스타 구로본점');
});
test('각 단계별 지연 시간이 적용되는지 확인', () async {
// Given
const url = 'https://naver.me/xtest1234';
const finalUrl = 'https://map.naver.com/p/restaurant/1234567890';
const placeId = '1234567890';
const placeName = '테스트 식당';
// 모든 단계 설정
mockApiClient.setUrlRedirect(url, finalUrl);
mockApiClient.setFinalRedirectUrl(
'https://map.naver.com/p/entry/place/$placeId',
'https://pcmap.place.naver.com/place/$placeId/home'
'https://pcmap.place.naver.com/place/$placeId/home',
);
mockApiClient.setSecondKoreanText(
'https://pcmap.place.naver.com/place/$placeId/home',
placeName
placeName,
);
mockApiClient.setSearchResults(placeName, [
NaverLocalSearchResult(
@@ -150,15 +149,14 @@ void main() {
mapy: 375666805,
),
]);
// When
final stopwatch = Stopwatch()..start();
await parser.parseRestaurantFromUrl(url);
stopwatch.stop();
// Then - 최소 지연 시간 확인 (500ms * 3 = 1500ms 이상)
expect(stopwatch.elapsedMilliseconds, greaterThanOrEqualTo(1500));
});
});
}