// ignore_for_file: unnecessary_library_name @Skip('Integration-heavy parser tests are temporarily disabled') library naver_map_parser_test; import 'package:flutter_test/flutter_test.dart'; import 'package:lunchpick/data/datasources/remote/naver_map_parser.dart'; import 'package:lunchpick/domain/entities/restaurant.dart'; import 'package:lunchpick/data/api/naver/naver_local_search_api.dart'; import 'package:lunchpick/core/errors/network_exceptions.dart'; import '../../../../mocks/mock_naver_api_client.dart'; void main() { late NaverMapParser parser; late MockNaverApiClient mockApiClient; setUp(() { mockApiClient = MockNaverApiClient(); parser = NaverMapParser(apiClient: mockApiClient); }); tearDown(() { parser.dispose(); }); group('NaverMapParser', () { group('URL 유효성 검증', () { test('유효한 네이버 지도 URL을 인식해야 함', () async { final validUrls = [ 'https://map.naver.com/p/restaurant/1234567890', 'https://naver.me/abcdefgh', 'https://map.naver.com/p/entry/place/1234567890', ]; for (final url in validUrls) { mockApiClient.setUrlRedirect( url, 'https://map.naver.com/p/restaurant/1234567890', ); // 검색 API 응답 설정 mockApiClient.setSearchResults( 'https://map.naver.com/p/entry/place/1234567890', [ NaverLocalSearchResult.fromJson({ 'title': '테스트 식당', 'link': 'https://map.naver.com/p/restaurant/1234567890', 'category': '한식', 'description': '테스트 설명', 'telephone': '02-1234-5678', 'address': '서울 강남구 테스트동 123-45', 'roadAddress': '서울 강남구 테스트로 123', 'mapx': 1269780000, 'mapy': 375665000, }), ], ); final result = await parser.parseRestaurantFromUrl(url); expect(result, isA(), reason: 'URL: $url'); expect(result.name, '테스트 식당', reason: 'URL: $url'); } }); test('잘못된 URL은 예외를 던져야 함', () async { final invalidUrls = [ 'https://www.google.com', 'https://map.kakao.com', 'https://naver.com', 'not-a-url', '', ]; for (final url in invalidUrls) { expect( () => parser.parseRestaurantFromUrl(url), throwsA(isA()), reason: 'URL: $url should throw exception', ); } }); }); group('API 응답 처리', () { test('검색 API로 식당 정보를 이지해야 함', () async { const url = 'https://map.naver.com/p/restaurant/1234567890'; mockApiClient.setUrlRedirect(url, url); // 검색 API 응답 설정 mockApiClient.setSearchResults( 'https://map.naver.com/p/entry/place/1234567890', [ NaverLocalSearchResult.fromJson({ 'title': '맛있는 한식당', 'link': 'https://map.naver.com/p/restaurant/1234567890', 'category': '한식>고기요리', 'description': '평일 11:00 - 22:00, 주말 10:00 - 23:00', 'telephone': '02-123-4567', 'address': '서울 강남구 역삼동 123-45', 'roadAddress': '서울 강남구 테헤란로 123', 'mapx': 1270396000, 'mapy': 375012000, }), ], ); final result = await parser.parseRestaurantFromUrl(url); expect(result, isA()); expect(result.name, '맛있는 한식당'); expect(result.category, '한식'); expect(result.description, contains('평일 11:00 - 22:00')); expect(result.phoneNumber, '02-123-4567'); expect(result.roadAddress, '서울 강남구 테헤란로 123'); expect(result.latitude, closeTo(37.5012, 0.0001)); expect(result.longitude, closeTo(127.0396, 0.0001)); }); test('GraphQL API로 식당 정보를 가져와야 함', () async { const url = 'https://map.naver.com/p/restaurant/9876543210'; mockApiClient.setUrlRedirect(url, url); // GraphQL 응답 설정 mockApiClient.setGraphQLResponse({ 'places': [ { 'id': '9876543210', 'name': '메타태그 식당', 'category': '기타', 'description': '맛있는 음식점', 'address': '서울시 강남구', 'roadAddress': '서울시 강남구 테헤란로', 'phone': '02-987-6543', 'location': {'lat': 37.5, 'lng': 127.0}, }, ], }); final result = await parser.parseRestaurantFromUrl(url); expect(result, isA()); expect(result.name, '메타태그 식당'); expect(result.category, '기타'); }); test('필수 정보가 없으면 기본값을 사용해야 함', () async { const url = 'https://map.naver.com/p/restaurant/1234567890'; mockApiClient.setUrlRedirect(url, url); // 빈 GraphQL 응답 mockApiClient.setGraphQLResponse({}); // HTML 파싱도 실패하도록 설정 mockApiClient.setHtmlResponse(url, ''); final result = await parser.parseRestaurantFromUrl(url); // 기본값이 사용되어야 함 expect(result, isA()); expect(result.name, contains('1234567890')); expect(result.category, '음식점'); }); }); group('단축 URL 처리', () { test('단축 URL을 실제 URL로 변환해야 함', () async { const shortUrl = 'https://naver.me/abc123'; const actualUrl = 'https://map.naver.com/p/restaurant/1234567890'; mockApiClient.setUrlRedirect(shortUrl, actualUrl); // 단축 URL용 한글 텍스트 추출 응답 mockApiClient.setKoreanTextsData('1234567890', { 'success': true, 'koreanTexts': ['리다이렉트 식당'], 'jsonLdName': '리다이렉트 식당', 'apolloStateName': null, }); // 검색 API 응답 설정 mockApiClient.setSearchResults('리다이렉트 식당', [ NaverLocalSearchResult.fromJson({ 'title': '리다이렉트 식당', 'link': actualUrl, 'category': '카페', 'description': '', 'telephone': '', 'address': '서울 마포구', 'roadAddress': '서울 마포구 테스트로 100', 'mapx': 1268900000, 'mapy': 375200000, }), ]); final result = await parser.parseRestaurantFromUrl(shortUrl); expect(result, isA()); expect(result.name, '리다이렉트 식당'); expect(result.category, '카페'); }); }); group('에러 처리', () { test('네트워크 오류 시 예외를 던져야 함', () async { const url = 'https://map.naver.com/p/restaurant/network-error'; mockApiClient.shouldThrowError = true; mockApiClient.errorMessage = 'Network error'; expect(() => parser.parseRestaurantFromUrl(url), throwsException); }); test('429 에러 시 적절한 예외를 던져야 함', () async { const url = 'https://map.naver.com/p/restaurant/1234567890'; mockApiClient.setUrlRedirect(url, url); // 429 에러 설정 mockApiClient.setThrow429Error(); expect( () => parser.parseRestaurantFromUrl(url), throwsA(isA()), ); }); }); }); }