From cf7f97545908aa01b1ee3dd8452ca7decd9c0622 Mon Sep 17 00:00:00 2001 From: Jack Alto Date: Fri, 23 Feb 2024 14:08:24 -0500 Subject: [PATCH] Update unit tests for search-box API type, add mock data - Add name prefixes for SBS_ and SearchBox_. - To display in the Xcode UI test classes must coexist in the global namespace so we have to use old-fashioned prefixes. - Add note to reorganize SBS mock data in the future. - Add SearchBoxMockResponse, initially based on SBS, to provide data for search-box API tests. - Fix namespace collision within MockWebServer.setResponse function clobbering response function argument. --- MapboxSearch.xcodeproj/project.pbxproj | 80 +- ...CategorySearchEngineIntegrationTests.swift | 2 +- .../SearchEngineIntegrationTests.swift | 2 +- ...CategorySearchEngineIntegrationTests.swift | 55 ++ ...archBox_SearchEngineIntegrationTests.swift | 194 +++++ .../Extensions/CoreApiType+ToSDKType.swift | 5 +- .../MockWebServer/MockResponse.swift | 122 +++ .../MockWebServer/MockWebServer.swift | 8 +- .../MockData/sbs/move-existing-mocks-here.txt | 1 + .../search-box/search-box-category.json | 819 ++++++++++++++++++ .../search-box/search-box-recursion.json | 62 ++ .../search-box/search-box-retrieve-minsk.json | 53 ++ .../search-box-suggestions-minsk.json | 408 +++++++++ 13 files changed, 1800 insertions(+), 11 deletions(-) create mode 100644 Tests/MapboxSearchIntegrationTests/search-box/SearchBox_CategorySearchEngineIntegrationTests.swift create mode 100644 Tests/MapboxSearchIntegrationTests/search-box/SearchBox_SearchEngineIntegrationTests.swift create mode 100644 Tests/MockData/sbs/move-existing-mocks-here.txt create mode 100644 Tests/MockData/search-box/search-box-category.json create mode 100644 Tests/MockData/search-box/search-box-recursion.json create mode 100644 Tests/MockData/search-box/search-box-retrieve-minsk.json create mode 100644 Tests/MockData/search-box/search-box-suggestions-minsk.json diff --git a/MapboxSearch.xcodeproj/project.pbxproj b/MapboxSearch.xcodeproj/project.pbxproj index e18a9aea6..a230d1258 100644 --- a/MapboxSearch.xcodeproj/project.pbxproj +++ b/MapboxSearch.xcodeproj/project.pbxproj @@ -15,14 +15,28 @@ 045514C22B7D4B58000D88B9 /* CoreApiType+ToSDKType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 045514C12B7D4B58000D88B9 /* CoreApiType+ToSDKType.swift */; }; 045514C32B7D4B58000D88B9 /* CoreApiType+ToSDKType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 045514C12B7D4B58000D88B9 /* CoreApiType+ToSDKType.swift */; }; 045514C42B7D4B58000D88B9 /* CoreApiType+ToSDKType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 045514C12B7D4B58000D88B9 /* CoreApiType+ToSDKType.swift */; }; + 046818D42B87F2A70082B188 /* SearchBox_CategorySearchEngineIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 046818D32B87F2A70082B188 /* SearchBox_CategorySearchEngineIntegrationTests.swift */; }; + 046818DB2B87FAB20082B188 /* search-box-category.json in Resources */ = {isa = PBXBuildFile; fileRef = 046818DA2B87FAB20082B188 /* search-box-category.json */; }; + 046818DC2B87FAB20082B188 /* search-box-category.json in Resources */ = {isa = PBXBuildFile; fileRef = 046818DA2B87FAB20082B188 /* search-box-category.json */; }; + 046818DD2B87FAB20082B188 /* search-box-category.json in Resources */ = {isa = PBXBuildFile; fileRef = 046818DA2B87FAB20082B188 /* search-box-category.json */; }; + 046818DF2B87FDC00082B188 /* SearchBox_SearchEngineIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 046818DE2B87FDC00082B188 /* SearchBox_SearchEngineIntegrationTests.swift */; }; + 046818E12B87FF5C0082B188 /* search-box-suggestions-minsk.json in Resources */ = {isa = PBXBuildFile; fileRef = 046818E02B87FF5C0082B188 /* search-box-suggestions-minsk.json */; }; + 046818E22B87FF5C0082B188 /* search-box-suggestions-minsk.json in Resources */ = {isa = PBXBuildFile; fileRef = 046818E02B87FF5C0082B188 /* search-box-suggestions-minsk.json */; }; + 046818E32B87FF5C0082B188 /* search-box-suggestions-minsk.json in Resources */ = {isa = PBXBuildFile; fileRef = 046818E02B87FF5C0082B188 /* search-box-suggestions-minsk.json */; }; + 047790492B890A8500A99528 /* search-box-recursion.json in Resources */ = {isa = PBXBuildFile; fileRef = 047790482B890A8500A99528 /* search-box-recursion.json */; }; + 0477904A2B890A8500A99528 /* search-box-recursion.json in Resources */ = {isa = PBXBuildFile; fileRef = 047790482B890A8500A99528 /* search-box-recursion.json */; }; + 0477904B2B890A8500A99528 /* search-box-recursion.json in Resources */ = {isa = PBXBuildFile; fileRef = 047790482B890A8500A99528 /* search-box-recursion.json */; }; + 0477904D2B890F4E00A99528 /* search-box-retrieve-minsk.json in Resources */ = {isa = PBXBuildFile; fileRef = 0477904C2B890F4E00A99528 /* search-box-retrieve-minsk.json */; }; + 0477904E2B890F4E00A99528 /* search-box-retrieve-minsk.json in Resources */ = {isa = PBXBuildFile; fileRef = 0477904C2B890F4E00A99528 /* search-box-retrieve-minsk.json */; }; + 0477904F2B890F4E00A99528 /* search-box-retrieve-minsk.json in Resources */ = {isa = PBXBuildFile; fileRef = 0477904C2B890F4E00A99528 /* search-box-retrieve-minsk.json */; }; 048823482B6B0A9D00C770AA /* category-hotel-search-along-route-jp.json in Resources */ = {isa = PBXBuildFile; fileRef = 04AB0B7C2B6B043C00FDE7D5 /* category-hotel-search-along-route-jp.json */; }; 048823492B6B0A9D00C770AA /* category-hotel-search-along-route-jp.json in Resources */ = {isa = PBXBuildFile; fileRef = 04AB0B7C2B6B043C00FDE7D5 /* category-hotel-search-along-route-jp.json */; }; 0488234A2B6B0A9E00C770AA /* category-hotel-search-along-route-jp.json in Resources */ = {isa = PBXBuildFile; fileRef = 04AB0B7C2B6B043C00FDE7D5 /* category-hotel-search-along-route-jp.json */; }; - 04AB0B7B2B6AF43E00FDE7D5 /* DiscoverIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04AB0B792B6AF37800FDE7D5 /* DiscoverIntegrationTests.swift */; }; 04970F8D2B7A97C900213763 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 04970F8C2B7A97C900213763 /* PrivacyInfo.xcprivacy */; }; 04AB0B4B2B6AADB700FDE7D5 /* mapbox.places.san.francisco.json in Resources */ = {isa = PBXBuildFile; fileRef = 04AB0B4A2B6AADB700FDE7D5 /* mapbox.places.san.francisco.json */; }; 04AB0B4C2B6AADB700FDE7D5 /* mapbox.places.san.francisco.json in Resources */ = {isa = PBXBuildFile; fileRef = 04AB0B4A2B6AADB700FDE7D5 /* mapbox.places.san.francisco.json */; }; 04AB0B4D2B6AADB700FDE7D5 /* mapbox.places.san.francisco.json in Resources */ = {isa = PBXBuildFile; fileRef = 04AB0B4A2B6AADB700FDE7D5 /* mapbox.places.san.francisco.json */; }; + 04AB0B7B2B6AF43E00FDE7D5 /* DiscoverIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04AB0B792B6AF37800FDE7D5 /* DiscoverIntegrationTests.swift */; }; 04BBC6342B61898F00E24E99 /* LocalhostMockServiceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BBC6332B61898F00E24E99 /* LocalhostMockServiceProvider.swift */; }; 04BBC6372B61ABA500E24E99 /* FeedbackIntegrationTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9BBFBD02604A4A500DE9C98 /* FeedbackIntegrationTestCase.swift */; }; 04C0848D2B4C82F3002F9C69 /* SdkInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C0848C2B4C82F3002F9C69 /* SdkInformation.swift */; }; @@ -502,10 +516,17 @@ 042477C42B72CCB000D870D5 /* geocoding-reverse-geocoding.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "geocoding-reverse-geocoding.json"; sourceTree = ""; }; 043A3D4C2B30F38300DB681B /* CoreAddress+AddressComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CoreAddress+AddressComponents.swift"; sourceTree = ""; }; 045514C12B7D4B58000D88B9 /* CoreApiType+ToSDKType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CoreApiType+ToSDKType.swift"; sourceTree = ""; }; - 04AB0B792B6AF37800FDE7D5 /* DiscoverIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverIntegrationTests.swift; sourceTree = ""; }; - 04AB0B7C2B6B043C00FDE7D5 /* category-hotel-search-along-route-jp.json */ = {isa = PBXFileReference; explicitFileType = text.json; path = "category-hotel-search-along-route-jp.json"; sourceTree = ""; }; + 046818D32B87F2A70082B188 /* SearchBox_CategorySearchEngineIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBox_CategorySearchEngineIntegrationTests.swift; sourceTree = ""; }; + 046818D82B87FA6E0082B188 /* move-existing-mocks-here.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "move-existing-mocks-here.txt"; sourceTree = ""; }; + 046818DA2B87FAB20082B188 /* search-box-category.json */ = {isa = PBXFileReference; explicitFileType = text.json; path = "search-box-category.json"; sourceTree = ""; }; + 046818DE2B87FDC00082B188 /* SearchBox_SearchEngineIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBox_SearchEngineIntegrationTests.swift; sourceTree = ""; }; + 046818E02B87FF5C0082B188 /* search-box-suggestions-minsk.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "search-box-suggestions-minsk.json"; sourceTree = ""; }; + 047790482B890A8500A99528 /* search-box-recursion.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "search-box-recursion.json"; sourceTree = ""; }; + 0477904C2B890F4E00A99528 /* search-box-retrieve-minsk.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "search-box-retrieve-minsk.json"; sourceTree = ""; }; 04970F8C2B7A97C900213763 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 04AB0B4A2B6AADB700FDE7D5 /* mapbox.places.san.francisco.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = mapbox.places.san.francisco.json; sourceTree = ""; }; + 04AB0B792B6AF37800FDE7D5 /* DiscoverIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverIntegrationTests.swift; sourceTree = ""; }; + 04AB0B7C2B6B043C00FDE7D5 /* category-hotel-search-along-route-jp.json */ = {isa = PBXFileReference; explicitFileType = text.json; path = "category-hotel-search-along-route-jp.json"; sourceTree = ""; }; 04BBC6332B61898F00E24E99 /* LocalhostMockServiceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalhostMockServiceProvider.swift; sourceTree = ""; }; 04C0848C2B4C82F3002F9C69 /* SdkInformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SdkInformation.swift; sourceTree = ""; }; 04C127542B62F6BC00884325 /* ApiType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiType.swift; sourceTree = ""; }; @@ -932,6 +953,43 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 046818D22B87F2810082B188 /* search-box */ = { + isa = PBXGroup; + children = ( + 046818D32B87F2A70082B188 /* SearchBox_CategorySearchEngineIntegrationTests.swift */, + 046818DE2B87FDC00082B188 /* SearchBox_SearchEngineIntegrationTests.swift */, + ); + path = "search-box"; + sourceTree = ""; + }; + 046818D52B87FA2E0082B188 /* MockData */ = { + isa = PBXGroup; + children = ( + 046818D72B87FA4F0082B188 /* sbs */, + 046818D62B87FA450082B188 /* search-box */, + ); + path = MockData; + sourceTree = ""; + }; + 046818D62B87FA450082B188 /* search-box */ = { + isa = PBXGroup; + children = ( + 046818DA2B87FAB20082B188 /* search-box-category.json */, + 046818E02B87FF5C0082B188 /* search-box-suggestions-minsk.json */, + 047790482B890A8500A99528 /* search-box-recursion.json */, + 0477904C2B890F4E00A99528 /* search-box-retrieve-minsk.json */, + ); + path = "search-box"; + sourceTree = ""; + }; + 046818D72B87FA4F0082B188 /* sbs */ = { + isa = PBXGroup; + children = ( + 046818D82B87FA6E0082B188 /* move-existing-mocks-here.txt */, + ); + path = sbs; + sourceTree = ""; + }; 04970F8B2B7A97C900213763 /* Resources */ = { isa = PBXGroup; children = ( @@ -1533,6 +1591,7 @@ F9ACA6162642C18200F50CD4 /* SearchEngineIntegrationTests.swift */, 042477C12B7290E700D870D5 /* SearchEngineGeocodingIntegrationTests.swift */, F99190422645ABE6009927A6 /* CategorySearchEngineIntegrationTests.swift */, + 046818D22B87F2810082B188 /* search-box */, 04AB0B792B6AF37800FDE7D5 /* DiscoverIntegrationTests.swift */, F9C5572C2670C88E00BE8B94 /* Info.plist */, ); @@ -1800,6 +1859,7 @@ FEEDD3842508E22800DC0A98 /* Tests */ = { isa = PBXGroup; children = ( + 046818D52B87FA2E0082B188 /* MockData */, FEF87CF7254C362200AD97AB /* CI-dev.xctestplan */, FEF87CEC254C35EC00AD97AB /* Demo.xctestplan */, F9C557292670C88E00BE8B94 /* MapboxSearchIntegrationTests */, @@ -2116,9 +2176,11 @@ F94FFA4A264547CD0019ED9B /* retrieve-multi.json in Resources */, 042477C62B72CCB000D870D5 /* geocoding-reverse-geocoding.json in Resources */, 2CD8AC4429F1D38800C47BE4 /* suggestions-category-with-coordinates.json in Resources */, + 0477904A2B890A8500A99528 /* search-box-recursion.json in Resources */, F9B62CCB264BCC2600492999 /* suggestions-empty.json in Resources */, 048823492B6B0A9D00C770AA /* category-hotel-search-along-route-jp.json in Resources */, 04AB0B4C2B6AADB700FDE7D5 /* mapbox.places.san.francisco.json in Resources */, + 046818DC2B87FAB20082B188 /* search-box-category.json in Resources */, F9ACA6182642C48C00F50CD4 /* recursion.json in Resources */, F9B62CC8264BC61600492999 /* category-cafe.json in Resources */, F9ACA6192642C49000F50CD4 /* retrieve-category.json in Resources */, @@ -2127,7 +2189,9 @@ 2CD8AC4A29F1D38800C47BE4 /* suggestions-with-mixed-coordinates.json in Resources */, 2CD8AC5329F28D6900C47BE4 /* retrieve-poi.json in Resources */, F9ACA61A2642C49300F50CD4 /* retrieve-san-francisco.json in Resources */, + 046818E22B87FF5C0082B188 /* search-box-suggestions-minsk.json in Resources */, 2CD8AC4729F1D38800C47BE4 /* suggestions-with-coordinates.json in Resources */, + 0477904E2B890F4E00A99528 /* search-box-retrieve-minsk.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2147,12 +2211,16 @@ F9B62CC9264BC61600492999 /* category-cafe.json in Resources */, F907440F261B00000091899C /* suggestions-san-francisco.json in Resources */, F94FFA4826453D410019ED9B /* reverse-geocoding-sbs.json in Resources */, + 046818E32B87FF5C0082B188 /* search-box-suggestions-minsk.json in Resources */, 2CD8AC4B29F1D38800C47BE4 /* suggestions-with-mixed-coordinates.json in Resources */, + 0477904B2B890A8500A99528 /* search-box-recursion.json in Resources */, 0488234A2B6B0A9E00C770AA /* category-hotel-search-along-route-jp.json in Resources */, 2CD8AC5429F28D6900C47BE4 /* retrieve-poi.json in Resources */, + 046818DD2B87FAB20082B188 /* search-box-category.json in Resources */, 042477C72B72CCB000D870D5 /* geocoding-reverse-geocoding.json in Resources */, F9074425261B0DF70091899C /* retrieve-san-francisco.json in Resources */, 2CD8AC4829F1D38800C47BE4 /* suggestions-with-coordinates.json in Resources */, + 0477904F2B890F4E00A99528 /* search-box-retrieve-minsk.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2168,9 +2236,11 @@ F9C557A42670CB0400BE8B94 /* retrieve-multi.json in Resources */, 042477C52B72CCB000D870D5 /* geocoding-reverse-geocoding.json in Resources */, 2CD8AC4329F1D38800C47BE4 /* suggestions-category-with-coordinates.json in Resources */, + 047790492B890A8500A99528 /* search-box-recursion.json in Resources */, F9C557A52670CB0400BE8B94 /* suggestions-empty.json in Resources */, 048823482B6B0A9D00C770AA /* category-hotel-search-along-route-jp.json in Resources */, 04AB0B4B2B6AADB700FDE7D5 /* mapbox.places.san.francisco.json in Resources */, + 046818DB2B87FAB20082B188 /* search-box-category.json in Resources */, F9C557A62670CB0400BE8B94 /* recursion.json in Resources */, F9C557A72670CB0400BE8B94 /* category-cafe.json in Resources */, F9C557A82670CB0400BE8B94 /* retrieve-category.json in Resources */, @@ -2179,7 +2249,9 @@ 2CD8AC4929F1D38800C47BE4 /* suggestions-with-mixed-coordinates.json in Resources */, 2CD8AC5229F28D6900C47BE4 /* retrieve-poi.json in Resources */, F9C557AA2670CB0400BE8B94 /* retrieve-san-francisco.json in Resources */, + 046818E12B87FF5C0082B188 /* search-box-suggestions-minsk.json in Resources */, 2CD8AC4629F1D38800C47BE4 /* suggestions-with-coordinates.json in Resources */, + 0477904D2B890F4E00A99528 /* search-box-retrieve-minsk.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2703,7 +2775,9 @@ 14FA6589295368AF00056E5B /* CoreAddress+Extensions.swift in Sources */, F9C557C02670CD5E00BE8B94 /* Address+Samples.swift in Sources */, F914EE652743E4F400D4F173 /* CoreAliases.swift in Sources */, + 046818DF2B87FDC00082B188 /* SearchBox_SearchEngineIntegrationTests.swift in Sources */, F9C557B42670CB4000BE8B94 /* SearchEngineIntegrationTests.swift in Sources */, + 046818D42B87F2A70082B188 /* SearchBox_CategorySearchEngineIntegrationTests.swift in Sources */, F9274FF5273AA79700708F37 /* OfflineIntegrationTests.swift in Sources */, F9C557BE2670CD2B00BE8B94 /* CoreSearchResponseStub+Samples.swift in Sources */, F9C557B82670CC7700BE8B94 /* CoreSearchResponseStub.swift in Sources */, diff --git a/Tests/MapboxSearchIntegrationTests/CategorySearchEngineIntegrationTests.swift b/Tests/MapboxSearchIntegrationTests/CategorySearchEngineIntegrationTests.swift index eb7bb7f71..cccc5703b 100644 --- a/Tests/MapboxSearchIntegrationTests/CategorySearchEngineIntegrationTests.swift +++ b/Tests/MapboxSearchIntegrationTests/CategorySearchEngineIntegrationTests.swift @@ -2,7 +2,7 @@ import CoreLocation @testable import MapboxSearch import XCTest -final class CategorySearchEngineIntegrationTests: MockServerIntegrationTestCase { +final class SBS_CategorySearchEngineIntegrationTests: MockServerIntegrationTestCase { private var searchEngine: CategorySearchEngine! override func setUpWithError() throws { diff --git a/Tests/MapboxSearchIntegrationTests/SearchEngineIntegrationTests.swift b/Tests/MapboxSearchIntegrationTests/SearchEngineIntegrationTests.swift index 4de4971b4..109769e34 100644 --- a/Tests/MapboxSearchIntegrationTests/SearchEngineIntegrationTests.swift +++ b/Tests/MapboxSearchIntegrationTests/SearchEngineIntegrationTests.swift @@ -2,7 +2,7 @@ import CoreLocation @testable import MapboxSearch import XCTest -class SearchEngineIntegrationTests: MockServerIntegrationTestCase { +class SBS_SearchEngineIntegrationTests: MockServerIntegrationTestCase { let delegate = SearchEngineDelegateStub() var searchEngine: SearchEngine! diff --git a/Tests/MapboxSearchIntegrationTests/search-box/SearchBox_CategorySearchEngineIntegrationTests.swift b/Tests/MapboxSearchIntegrationTests/search-box/SearchBox_CategorySearchEngineIntegrationTests.swift new file mode 100644 index 000000000..9fdd0d777 --- /dev/null +++ b/Tests/MapboxSearchIntegrationTests/search-box/SearchBox_CategorySearchEngineIntegrationTests.swift @@ -0,0 +1,55 @@ +import CoreLocation +@testable import MapboxSearch +import XCTest + +final class SearchBox_CategorySearchEngineIntegrationTests: MockServerIntegrationTestCase { + private var searchEngine: CategorySearchEngine! + + override func setUpWithError() throws { + try super.setUpWithError() + + let apiType = try XCTUnwrap(Mock.coreApiType.toSDKType()) + searchEngine = CategorySearchEngine( + accessToken: "access-token", + serviceProvider: LocalhostMockServiceProvider.shared, + apiType: apiType + ) + } + + func testCategorySearch() throws { + try server.setResponse(.categoryCafe) + + let expectation = XCTestExpectation(description: "Expecting results") + searchEngine.search(categoryName: "cafe") { result in + switch result { + case .success(let searchResults): + XCTAssertFalse(searchResults.isEmpty) + expectation.fulfill() + case .failure: + XCTFail("Error not expected") + } + expectation.fulfill() + } + wait(for: [expectation], timeout: 10) + } + + func testCategorySearchFailed() throws { + try server.setResponse(.categoryCafe, statusCode: 500) + + let expectation = XCTestExpectation(description: "Expecting failure") + searchEngine.search(categoryName: "cafe") { result in + switch result { + case .success: + XCTFail("Not expected") + case .failure(let searchError): + if case .generic(let code, _, _) = searchError { + XCTAssert(code == 500) + } else { + XCTFail("Not expected") + } + } + expectation.fulfill() + } + wait(for: [expectation], timeout: 10) + } +} diff --git a/Tests/MapboxSearchIntegrationTests/search-box/SearchBox_SearchEngineIntegrationTests.swift b/Tests/MapboxSearchIntegrationTests/search-box/SearchBox_SearchEngineIntegrationTests.swift new file mode 100644 index 000000000..1c4472d94 --- /dev/null +++ b/Tests/MapboxSearchIntegrationTests/search-box/SearchBox_SearchEngineIntegrationTests.swift @@ -0,0 +1,194 @@ +import CoreLocation +@testable import MapboxSearch +import XCTest + +class SearchBox_SearchEngineIntegrationTests: MockServerIntegrationTestCase { + let delegate = SearchEngineDelegateStub() + var searchEngine: SearchEngine! + + override func setUpWithError() throws { + try super.setUpWithError() + + let apiType = try XCTUnwrap(Mock.coreApiType.toSDKType()) + searchEngine = SearchEngine( + accessToken: "access-token", + serviceProvider: LocalhostMockServiceProvider.shared, + locationProvider: DefaultLocationProvider(), + apiType: apiType + ) + + searchEngine.delegate = delegate + } + + func testNotFoundSearch() throws { + // No server response set, 404 error should be received + let expectation = delegate.errorExpectation + searchEngine.search(query: "some query") + wait(for: [expectation], timeout: 10) + + XCTAssert(delegate.error?.errorCode == 404) + XCTAssert(searchEngine.suggestions.isEmpty) + } + + func testSearchBrokenResponse() throws { + server.setResponse(endpoint: .suggestEmpty, body: "This is so sad!", statusCode: 200) + let expectation = delegate.errorExpectation + searchEngine.search(query: "some query") + wait(for: [expectation], timeout: 10) + + if case .internalSearchRequestError(let message) = delegate.error { + XCTAssert(message == "Invalid json response") + } else { + XCTFail("Not expected") + } + + XCTAssert(searchEngine.suggestions.isEmpty) + } + + func testSimpleSearch() throws { + try server.setResponse(.suggestMinsk) + + let expectation = delegate.updateExpectation + searchEngine.search(query: "Minsk") + wait(for: [expectation], timeout: 10) + + XCTAssert(searchEngine.suggestions.contains { $0.name == "Minsk" }) + } + + func testSimpleSearchFailed() throws { + try server.setResponse(.suggestMinsk, statusCode: 500) + + let expectation = delegate.errorExpectation + searchEngine.search(query: "Minsk") + wait(for: [expectation], timeout: 10) + + XCTAssert(searchEngine.suggestions.isEmpty) + XCTAssert(delegate.error?.errorCode == 500) + } + + func testEmptySearch() throws { + try server.setResponse(.suggestEmpty) + + let expectation = delegate.updateExpectation + searchEngine.search(query: "Minsk") + wait(for: [expectation], timeout: 10) + + XCTAssert(searchEngine.suggestions.isEmpty) + XCTAssertNil(delegate.error) + } + + func testResolvedSearchResult() throws { + try server.setResponse(.suggestMinsk) + try server.setResponse(.retrieveMinsk) + + let updateExpectation = delegate.updateExpectation + searchEngine.search(query: "Minsk") + wait(for: [updateExpectation], timeout: 10) + XCTAssertFalse(searchEngine.suggestions.isEmpty) + + let successExpectation = delegate.successExpectation + let selectedResult = try XCTUnwrap(searchEngine.suggestions.first) + searchEngine.select(suggestion: selectedResult) + + wait(for: [successExpectation], timeout: 10) + let resolvedResult = try XCTUnwrap(delegate.resolvedResult) + + XCTAssertEqual(resolvedResult.name, selectedResult.name) + } + + func testResolvedSearchResultWhenQueryChanged() throws { + try server.setResponse(.suggestMinsk) + try server.setResponse(.retrieveMinsk) + + searchEngine.search(query: "Minsk") + + let updateExpectation = delegate.updateExpectation + wait(for: [updateExpectation], timeout: 10) + + XCTAssertFalse(searchEngine.suggestions.isEmpty) + let selectedResult = try XCTUnwrap(searchEngine.suggestions.first) + + searchEngine.search(query: "Min") + searchEngine.select(suggestion: selectedResult) + + let successExpectation = delegate.successExpectation + wait(for: [successExpectation], timeout: 10) + + let resolvedResult = try XCTUnwrap(delegate.resolvedResult) + XCTAssertEqual(resolvedResult.name, selectedResult.name) + } + + func testResolvedSearchResultFailed() throws { + try server.setResponse(.suggestMinsk) + try server.setResponse(.retrieveMinsk, statusCode: 500) + + let updateExpectation = delegate.updateExpectation + searchEngine.search(query: "Minsk") + wait(for: [updateExpectation], timeout: 10) + XCTAssertFalse(searchEngine.suggestions.isEmpty) + + let errorExpectation = delegate.errorExpectation + let selectedResult = try XCTUnwrap(searchEngine.suggestions.first) + searchEngine.select(suggestion: selectedResult) + wait(for: [errorExpectation], timeout: 10) + + if case .resultResolutionFailed(let suggestion) = delegate.error { + XCTAssertEqual(selectedResult.id, suggestion.id) + XCTAssertEqual(selectedResult.name, suggestion.name) + XCTAssertEqual(selectedResult.address, suggestion.address) + } else { + XCTFail("Not expected") + } + + XCTAssertNil(delegate.resolvedResult) + } + + func testBatchResolve() throws { + try server.setResponse(.multiRetrieve) + + let results = CoreSearchResultStub.makeMixedResultsSet().map(\.asCoreSearchResult) + let coreResponse = CoreSearchResponseStub.successSample(results: results) + + let suggestions = CoreSearchResultStub.makeSuggestionsSet().map(\.asCoreSearchResult).compactMap { + SearchResultSuggestionImpl(coreResult: $0, response: coreResponse) + } + + let expectation = delegate.batchUpdateExpectation + searchEngine.select(suggestions: suggestions) + + wait(for: [expectation], timeout: 10) + XCTAssertFalse(delegate.resolvedResults.isEmpty) + } + + func testBatchResolveFailed() throws { + try server.setResponse(.multiRetrieve, statusCode: 500) + + let results = CoreSearchResultStub.makeMixedResultsSet().map(\.asCoreSearchResult) + let coreResponse = CoreSearchResponseStub.successSample(results: results) + + let suggestions = CoreSearchResultStub.makeSuggestionsSet().map(\.asCoreSearchResult).compactMap { + SearchResultSuggestionImpl(coreResult: $0, response: coreResponse) + } + + let expectation = delegate.errorExpectation + searchEngine.select(suggestions: suggestions) + + wait(for: [expectation], timeout: 10) + XCTAssert(delegate.error?.errorCode == 500) + } + + func testSuggestionTypeQuery() throws { + try server.setResponse(.recursion) + + let updateExpectation = delegate.updateExpectation + searchEngine.query = "Recursion" + wait(for: [updateExpectation], timeout: 10) + + let firstSuggestion = try XCTUnwrap(searchEngine.suggestions.first) + searchEngine.select(suggestion: firstSuggestion) + + let nextUpdateExpectation = delegate.updateExpectation + wait(for: [nextUpdateExpectation], timeout: 10) + XCTAssertFalse(searchEngine.suggestions.isEmpty) + } +} diff --git a/Tests/MapboxSearchTests/Common/Extensions/CoreApiType+ToSDKType.swift b/Tests/MapboxSearchTests/Common/Extensions/CoreApiType+ToSDKType.swift index e57f013db..5066d7229 100644 --- a/Tests/MapboxSearchTests/Common/Extensions/CoreApiType+ToSDKType.swift +++ b/Tests/MapboxSearchTests/Common/Extensions/CoreApiType+ToSDKType.swift @@ -16,8 +16,9 @@ extension CoreSearchEngine.ApiType { return .geocoding case .SBS: return .SBS - case .autofill, - .searchBox: + case .searchBox: + return .searchBox + case .autofill: fallthrough @unknown default: fatalError() diff --git a/Tests/MapboxSearchUITests/MockWebServer/MockResponse.swift b/Tests/MapboxSearchUITests/MockWebServer/MockResponse.swift index b5ed5ec5a..d2ca507f7 100644 --- a/Tests/MapboxSearchUITests/MockWebServer/MockResponse.swift +++ b/Tests/MapboxSearchUITests/MockWebServer/MockResponse.swift @@ -187,6 +187,128 @@ enum SBSMockResponse: MockResponse { } } +// MARK: - search-box + +enum SearchBoxMockResponse: MockResponse { + case suggestEmpty + case suggestMinsk + case suggestSanFrancisco + case suggestCategories + case suggestWithCoordinates + case suggestWithMixedCoordinates + case suggestCategoryWithCoordinates + + case retrieveSanFrancisco + case retrieveMinsk + case retrieveCategory + case retrievePoi + case multiRetrieve + + case recursion + case categoryCafe + case categoryHotelSearchAlongRoute_JP + + var filepath: String { + let bundle = Bundle(for: MockWebServer.self) + switch self { + case .suggestEmpty: + return bundle.path(forResource: "suggestions-empty", ofType: "json")! + case .suggestMinsk: + return bundle.path(forResource: "search-box-suggestions-minsk", ofType: "json")! + case .suggestSanFrancisco: + return bundle.path(forResource: "suggestions-san-francisco", ofType: "json")! + case .suggestCategories: + return bundle.path(forResource: "suggestions-categories", ofType: "json")! + case .suggestWithCoordinates: + return bundle.path(forResource: "suggestions-with-coordinates", ofType: "json")! + case .suggestWithMixedCoordinates: + return bundle.path(forResource: "suggestions-with-mixed-coordinates", ofType: "json")! + case .suggestCategoryWithCoordinates: + return bundle.path(forResource: "suggestions-category-with-coordinates", ofType: "json")! + case .retrieveSanFrancisco: + return bundle.path(forResource: "retrieve-san-francisco", ofType: "json")! + case .retrieveMinsk: + return bundle.path(forResource: "search-box-retrieve-minsk", ofType: "json")! + case .retrieveCategory: + return bundle.path(forResource: "retrieve-category", ofType: "json")! + case .retrievePoi: + return bundle.path(forResource: "retrieve-poi", ofType: "json")! + case .recursion: + return bundle.path(forResource: "search-box-recursion", ofType: "json")! + case .multiRetrieve: + return bundle.path(forResource: "retrieve-multi", ofType: "json")! + case .categoryCafe: + return bundle.path(forResource: "search-box-category", ofType: "json")! + case .categoryHotelSearchAlongRoute_JP: + return bundle.path(forResource: "category-hotel-search-along-route-jp", ofType: "json")! + } + } + + var path: String { + var path = "/search/searchbox/v1" + + switch self { + case .suggestMinsk: + path += "/suggest?q=Minsk" + + case .suggestSanFrancisco: + path += "/suggest/San Francisco" + + case .recursion: + path += "/suggest?q=Recursion" + + case .suggestEmpty, + .suggestCategories, + .suggestWithCoordinates, + .suggestWithMixedCoordinates, + .suggestCategoryWithCoordinates: + path += "/suggest?q=:query" + + case .retrieveSanFrancisco, + .retrieveCategory, + .retrieveMinsk, + .retrievePoi: + path += "/retrieve/:identifier" + + case .multiRetrieve: + path += "/retrieve/multi" + + case .categoryCafe, + .categoryHotelSearchAlongRoute_JP: + path += "/category/:category" + } + + return path + } + + var httpMethod: HttpServer.HTTPMethod { + switch self { + case .suggestMinsk, + .suggestSanFrancisco, + .suggestEmpty, + .suggestCategories, + .suggestWithCoordinates, + .suggestWithMixedCoordinates, + .suggestCategoryWithCoordinates, + .recursion, + .categoryCafe, + .categoryHotelSearchAlongRoute_JP, + .retrieveMinsk: + return .get + + case .multiRetrieve, + .retrieveSanFrancisco, + .retrieveCategory, + .retrievePoi: + return .post + } + } + + static var coreApiType: CoreSearchEngine.ApiType { + .searchBox + } +} + // MARK: - Autofill enum AutofillMockResponse: MockResponse { diff --git a/Tests/MapboxSearchUITests/MockWebServer/MockWebServer.swift b/Tests/MapboxSearchUITests/MockWebServer/MockWebServer.swift index 29d646003..727fb082d 100644 --- a/Tests/MapboxSearchUITests/MockWebServer/MockWebServer.swift +++ b/Tests/MapboxSearchUITests/MockWebServer/MockWebServer.swift @@ -6,13 +6,13 @@ final class MockWebServer { private let server = HttpServer() - func setResponse(_ response: Mock, query: String? = nil, statusCode: Int = 200) throws { - let route = response.path - let method = response.httpMethod + func setResponse(_ endpoint: Mock, query: String? = nil, statusCode: Int = 200) throws { + let route = endpoint.path + let method = endpoint.httpMethod let response = HttpResponse.raw(statusCode, "mocked response", nil) { writer in try writer.write( - Data(contentsOf: URL(fileURLWithPath: response.filepath)) + Data(contentsOf: URL(fileURLWithPath: endpoint.filepath)) ) } diff --git a/Tests/MockData/sbs/move-existing-mocks-here.txt b/Tests/MockData/sbs/move-existing-mocks-here.txt new file mode 100644 index 000000000..7f1feb34e --- /dev/null +++ b/Tests/MockData/sbs/move-existing-mocks-here.txt @@ -0,0 +1 @@ +// TODO: Move existing SBS mock JOSN files here in a dedicated PR with no other changes to reduce noise diff --git a/Tests/MockData/search-box/search-box-category.json b/Tests/MockData/search-box/search-box-category.json new file mode 100644 index 000000000..82d93ea6c --- /dev/null +++ b/Tests/MockData/search-box/search-box-category.json @@ -0,0 +1,819 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "coordinates": [ + -122.40735626220705, + 37.78680038452149 + ], + "type": "Point" + }, + "properties": { + "name": "Starbucks", + "mapbox_id": "dXJuOm1ieHBvaTpjN2RmMGU5NC1iYWIxLTQ3OTMtODg1OS1hZDljNjg5ZWY1Yjg", + "feature_type": "poi", + "address": "170 O'farrell Street", + "full_address": "170 O'farrell Street, San Francisco, California 94102, United States", + "place_formatted": "San Francisco, California 94102, United States", + "context": { + "country": { + "name": "United States", + "country_code": "US", + "country_code_alpha_3": "USA" + }, + "region": { + "name": "California", + "region_code": "CA", + "region_code_full": "US-CA" + }, + "postcode": { + "id": "dXJuOm1ieHBsYzpFcDh1N0E", + "name": "94102" + }, + "place": { + "id": "dXJuOm1ieHBsYzpFVzBJN0E", + "name": "San Francisco" + }, + "neighborhood": { + "id": "dXJuOm1ieHBsYzpDaTBzN0E", + "name": "Downtown" + }, + "address": { + "name": "170 O'farrell Street", + "address_number": "170", + "street_name": "o'farrell street" + }, + "street": { + "name": "o'farrell street" + } + }, + "coordinates": { + "latitude": 37.78680038452149, + "longitude": -122.40735626220705, + "routable_points": [ + { + "name": "default", + "latitude": 37.786528, + "longitude": -122.407305 + } + ] + }, + "language": "", + "maki": "restaurant", + "poi_category": [ + "bakery", + "café", + "coffee", + "coffee shop", + "food", + "food and drink", + "teahouse" + ], + "poi_category_ids": [ + "bakery", + "cafe", + "coffee", + "coffee_shop", + "food", + "food_and_drink", + "teahouse" + ], + "brand": [ + "Starbucks", + "สตาร์บัคส์", + "星巴克", + "スターバックス", + "ستاربكس" + ], + "brand_id": [ + "starbucks" + ], + "external_ids": { + "safegraph": "22c-222@5vg-7gw-v4v", + "foursquare": "4a6a452ef964a52001cd1fe3" + }, + "metadata": { + "phone": "+14159229086", + "website": "https://www.starbucks.com/store-locator/store/11405", + "open_hours": { + "periods": [ + { + "open": { + "day": 0, + "time": "0400" + }, + "close": { + "day": 0, + "time": "2330" + } + }, + { + "open": { + "day": 1, + "time": "0400" + }, + "close": { + "day": 1, + "time": "2330" + } + }, + { + "open": { + "day": 2, + "time": "0400" + }, + "close": { + "day": 2, + "time": "2330" + } + }, + { + "open": { + "day": 3, + "time": "0400" + }, + "close": { + "day": 3, + "time": "2330" + } + }, + { + "open": { + "day": 4, + "time": "0400" + }, + "close": { + "day": 4, + "time": "2330" + } + }, + { + "open": { + "day": 5, + "time": "0400" + }, + "close": { + "day": 5, + "time": "2330" + } + }, + { + "open": { + "day": 6, + "time": "0400" + }, + "close": { + "day": 6, + "time": "2300" + } + } + ] + } + } + } + }, + { + "type": "Feature", + "geometry": { + "coordinates": [ + -122.411212, + 37.785707 + ], + "type": "Point" + }, + "properties": { + "name": "Taylor Street Coffee Shop", + "mapbox_id": "dXJuOm1ieHBvaTpmYTUxODI1ZS00NjgxLTQ4ZDQtYjUyZS1kODQ0NjJmOTBiZWE", + "feature_type": "poi", + "address": "375 Taylor St", + "full_address": "375 Taylor St, San Francisco, California 94102, United States", + "place_formatted": "San Francisco, California 94102, United States", + "context": { + "country": { + "name": "United States", + "country_code": "US", + "country_code_alpha_3": "USA" + }, + "region": { + "name": "California", + "region_code": "CA", + "region_code_full": "US-CA" + }, + "postcode": { + "id": "dXJuOm1ieHBsYzpFcDh1N0E", + "name": "94102" + }, + "place": { + "id": "dXJuOm1ieHBsYzpFVzBJN0E", + "name": "San Francisco" + }, + "neighborhood": { + "id": "dXJuOm1ieHBsYzpKaXhNN0E", + "name": "Tenderloin" + }, + "address": { + "name": "375 Taylor St", + "address_number": "375", + "street_name": "taylor st" + }, + "street": { + "name": "taylor st" + } + }, + "coordinates": { + "latitude": 37.785707, + "longitude": -122.411212, + "routable_points": [ + { + "name": "default", + "latitude": 37.78569263240253, + "longitude": -122.41128259224192 + } + ] + }, + "language": "", + "maki": "restaurant", + "poi_category": [ + "café", + "coffee", + "coffee shop", + "food", + "food and drink" + ], + "poi_category_ids": [ + "cafe", + "coffee", + "coffee_shop", + "food", + "food_and_drink" + ], + "external_ids": { + "foursquare": "4a671dbaf964a520edc81fe3", + "safegraph": "229-222@5vg-7gw-vfz" + }, + "metadata": { + "phone": "+14155674031", + "website": "http://taylor-street-coffee-shop.cafes-city.com", + "open_hours": { + "periods": [ + { + "open": { + "day": 0, + "time": "0700" + }, + "close": { + "day": 0, + "time": "1400" + } + }, + { + "open": { + "day": 1, + "time": "0700" + }, + "close": { + "day": 1, + "time": "1400" + } + }, + { + "open": { + "day": 2, + "time": "0700" + }, + "close": { + "day": 2, + "time": "1400" + } + }, + { + "open": { + "day": 3, + "time": "0700" + }, + "close": { + "day": 3, + "time": "1400" + } + }, + { + "open": { + "day": 4, + "time": "0700" + }, + "close": { + "day": 4, + "time": "1400" + } + }, + { + "open": { + "day": 5, + "time": "0700" + }, + "close": { + "day": 5, + "time": "1400" + } + }, + { + "open": { + "day": 6, + "time": "0700" + }, + "close": { + "day": 6, + "time": "1400" + } + } + ] + } + } + } + }, + { + "type": "Feature", + "geometry": { + "coordinates": [ + -122.403779, + 37.787396 + ], + "type": "Point" + }, + "properties": { + "name": "Mazarine Coffee", + "mapbox_id": "dXJuOm1ieHBvaTo2NTllNzc5ZC1jNTJjLTQ1ZjktOWQ0OC00YzRlZGQ0MmI0YjU", + "feature_type": "poi", + "address": "720 Market St", + "full_address": "720 Market St, San Francisco, California 94103, United States", + "place_formatted": "San Francisco, California 94103, United States", + "context": { + "country": { + "name": "United States", + "country_code": "US", + "country_code_alpha_3": "USA" + }, + "region": { + "name": "California", + "region_code": "CA", + "region_code_full": "US-CA" + }, + "postcode": { + "id": "dXJuOm1ieHBsYzpFcDlPN0E", + "name": "94103" + }, + "place": { + "id": "dXJuOm1ieHBsYzpFVzBJN0E", + "name": "San Francisco" + }, + "neighborhood": { + "id": "dXJuOm1ieHBsYzpMQ2tzN0E", + "name": "Yerba Buena" + }, + "address": { + "name": "720 Market St", + "address_number": "720", + "street_name": "market st" + }, + "street": { + "name": "market st" + } + }, + "coordinates": { + "latitude": 37.787396, + "longitude": -122.403779, + "routable_points": [ + { + "name": "default", + "latitude": 37.78740092927761, + "longitude": -122.40378290421192 + } + ] + }, + "language": "", + "maki": "restaurant", + "poi_category": [ + "café", + "coffee", + "coffee shop", + "food", + "food and drink" + ], + "poi_category_ids": [ + "cafe", + "coffee", + "coffee_shop", + "food", + "food_and_drink" + ], + "external_ids": { + "foursquare": "547cac4d498ecfcb0018b838", + "safegraph": "23p-222@5vg-7gv-5fz" + }, + "metadata": { + "phone": "(415) 398-7700", + "website": "http://www.mazarinecoffee.com", + "open_hours": { + "periods": [ + { + "open": { + "day": 0, + "time": "0700" + }, + "close": { + "day": 0, + "time": "1800" + } + }, + { + "open": { + "day": 1, + "time": "0700" + }, + "close": { + "day": 1, + "time": "1800" + } + }, + { + "open": { + "day": 2, + "time": "0700" + }, + "close": { + "day": 2, + "time": "1800" + } + }, + { + "open": { + "day": 3, + "time": "0700" + }, + "close": { + "day": 3, + "time": "1800" + } + }, + { + "open": { + "day": 4, + "time": "0700" + }, + "close": { + "day": 4, + "time": "1800" + } + }, + { + "open": { + "day": 5, + "time": "0800" + }, + "close": { + "day": 5, + "time": "1700" + } + }, + { + "open": { + "day": 6, + "time": "0800" + }, + "close": { + "day": 6, + "time": "1700" + } + } + ] + } + } + } + }, + { + "type": "Feature", + "geometry": { + "coordinates": [ + -122.414318, + 37.787682 + ], + "type": "Point" + }, + "properties": { + "name": "Farm Table", + "mapbox_id": "dXJuOm1ieHBvaTo4MmU0YzhiNC1iM2Y1LTQzZDItODZhNi1hMTFjNDM3ODIxNDI", + "feature_type": "poi", + "address": "754 Post St", + "full_address": "754 Post St, San Francisco, California 94109, United States", + "place_formatted": "San Francisco, California 94109, United States", + "context": { + "country": { + "name": "United States", + "country_code": "US", + "country_code_alpha_3": "USA" + }, + "region": { + "name": "California", + "region_code": "CA", + "region_code_full": "US-CA" + }, + "postcode": { + "id": "dXJuOm1ieHBsYzpFcC91N0E", + "name": "94109" + }, + "place": { + "id": "dXJuOm1ieHBsYzpFVzBJN0E", + "name": "San Francisco" + }, + "neighborhood": { + "id": "dXJuOm1ieHBsYzpGbFlNN0E", + "name": "Lower Nob Hill" + }, + "address": { + "name": "754 Post St", + "address_number": "754", + "street_name": "post st" + }, + "street": { + "name": "post st" + } + }, + "coordinates": { + "latitude": 37.787682, + "longitude": -122.414318, + "routable_points": [ + { + "name": "default", + "latitude": 37.78754840141576, + "longitude": -122.41430100137298 + } + ] + }, + "language": "", + "maki": "restaurant", + "poi_category": [ + "brunch restaurant", + "café", + "coffee", + "coffee shop", + "food", + "food and drink", + "restaurant" + ], + "poi_category_ids": [ + "brunch_restaurant", + "cafe", + "coffee", + "coffee_shop", + "food", + "food_and_drink", + "restaurant" + ], + "external_ids": { + "foursquare": "4b008eadf964a520733f22e3", + "safegraph": "22h-222@5vg-7gw-w49" + }, + "metadata": { + "phone": "+14153005652", + "website": "https://www.farmtablesf.com", + "open_hours": { + "periods": [ + { + "open": { + "day": 0, + "time": "0800" + }, + "close": { + "day": 0, + "time": "1200" + } + }, + { + "open": { + "day": 1, + "time": "0730" + }, + "close": { + "day": 1, + "time": "1400" + } + }, + { + "open": { + "day": 2, + "time": "0730" + }, + "close": { + "day": 2, + "time": "1400" + } + }, + { + "open": { + "day": 3, + "time": "0730" + }, + "close": { + "day": 3, + "time": "1400" + } + }, + { + "open": { + "day": 4, + "time": "0730" + }, + "close": { + "day": 4, + "time": "1400" + } + }, + { + "open": { + "day": 5, + "time": "0800" + }, + "close": { + "day": 5, + "time": "1500" + } + }, + { + "open": { + "day": 6, + "time": "0800" + }, + "close": { + "day": 6, + "time": "1500" + } + } + ] + } + } + } + }, + { + "type": "Feature", + "geometry": { + "coordinates": [ + -122.408545, + 37.776987 + ], + "type": "Point" + }, + "properties": { + "name": "Sightglass Coffee", + "mapbox_id": "dXJuOm1ieHBvaTo4MWExYTU2OC05NjZkLTQxMTQtYjliYy1mMzk3NTRkNWYyMzM", + "feature_type": "poi", + "address": "270 7th St", + "full_address": "270 7th St, San Francisco, California 94103, United States", + "place_formatted": "San Francisco, California 94103, United States", + "context": { + "country": { + "name": "United States", + "country_code": "US", + "country_code_alpha_3": "USA" + }, + "region": { + "name": "California", + "region_code": "CA", + "region_code_full": "US-CA" + }, + "postcode": { + "id": "dXJuOm1ieHBsYzpFcDlPN0E", + "name": "94103" + }, + "place": { + "id": "dXJuOm1ieHBsYzpFVzBJN0E", + "name": "San Francisco" + }, + "neighborhood": { + "id": "dXJuOm1ieHBsYzpJOWtzN0E", + "name": "South of Market" + }, + "address": { + "name": "270 7th St", + "address_number": "270", + "street_name": "7th st" + }, + "street": { + "name": "7th st" + } + }, + "coordinates": { + "latitude": 37.776987, + "longitude": -122.408545, + "routable_points": [ + { + "name": "default", + "latitude": 37.77718105334916, + "longitude": -122.4083903722148 + } + ] + }, + "language": "", + "maki": "restaurant", + "poi_category": [ + "café", + "coffee", + "coffee shop", + "food", + "food and drink" + ], + "poi_category_ids": [ + "cafe", + "coffee", + "coffee_shop", + "food", + "food_and_drink" + ], + "external_ids": { + "foursquare": "4a4b8a43f964a5206fac1fe3", + "safegraph": "22s-222@5vg-7gq-j5f" + }, + "metadata": { + "phone": "+14158611313", + "website": "http://sightglasscoffee.com", + "open_hours": { + "periods": [ + { + "open": { + "day": 0, + "time": "0700" + }, + "close": { + "day": 0, + "time": "1900" + } + }, + { + "open": { + "day": 1, + "time": "0700" + }, + "close": { + "day": 1, + "time": "1900" + } + }, + { + "open": { + "day": 2, + "time": "0700" + }, + "close": { + "day": 2, + "time": "1900" + } + }, + { + "open": { + "day": 3, + "time": "0700" + }, + "close": { + "day": 3, + "time": "1900" + } + }, + { + "open": { + "day": 4, + "time": "0700" + }, + "close": { + "day": 4, + "time": "1900" + } + }, + { + "open": { + "day": 5, + "time": "0700" + }, + "close": { + "day": 5, + "time": "1900" + } + }, + { + "open": { + "day": 6, + "time": "0800" + }, + "close": { + "day": 6, + "time": "1900" + } + } + ] + } + } + } + } + ], + "attribution": "© 2023 Mapbox and its suppliers. All rights reserved. Use of this data is subject to the Mapbox Terms of Service. (https://www.mapbox.com/about/maps/)" +} diff --git a/Tests/MockData/search-box/search-box-recursion.json b/Tests/MockData/search-box/search-box-recursion.json new file mode 100644 index 000000000..68eaa24b3 --- /dev/null +++ b/Tests/MockData/search-box/search-box-recursion.json @@ -0,0 +1,62 @@ +{ + "suggestions": [ + { + "name": "Recursion Software", + "name_preferred": "Recursion Software Inc", + "mapbox_id": "dXJuOm1ieHBvaTozZTkxYzBlNC0yOWI0LTQzMTUtODIxNS02Njc2MGVjNjUyZTY", + "feature_type": "poi", + "address": "2121 W Spring Creek Pkwy Ste 108", + "full_address": "2121 W Spring Creek Pkwy Ste 108, Plano, Texas 75023, United States", + "place_formatted": "Plano, Texas 75023, United States", + "context": { + "country": { + "name": "United States", + "country_code": "US", + "country_code_alpha_3": "USA" + }, + "region": { + "name": "Texas", + "region_code": "TX", + "region_code_full": "US-TX" + }, + "postcode": { + "id": "dXJuOm1ieHBsYzpEMDN1N0E", + "name": "75023" + }, + "place": { + "id": "dXJuOm1ieHBsYzpENWJJN0E", + "name": "Plano" + }, + "neighborhood": { + "id": "dXJuOm1ieHBsYzpFbE9zN0E", + "name": "Hunters Glen" + }, + "address": { + "name": "2121 W Spring Creek Pkwy Ste 108", + "address_number": "2121", + "street_name": "w spring creek pkwy" + }, + "street": { + "name": "w spring creek pkwy" + } + }, + "language": "en", + "maki": "marker", + "poi_category": [ + "information technology", + "office" + ], + "poi_category_ids": [ + "information_technology_company", + "office" + ], + "external_ids": { + "safegraph": "22f-222@5qv-xm8-99f", + "foursquare": "54fdaf28498eee5c95f80fdd" + }, + "metadata": {}, + "distance": 2380000 + }, + ], + "attribution": "© 2023 Mapbox and its suppliers. All rights reserved. Use of this data is subject to the Mapbox Terms of Service. (https://www.mapbox.com/about/maps/)" +} diff --git a/Tests/MockData/search-box/search-box-retrieve-minsk.json b/Tests/MockData/search-box/search-box-retrieve-minsk.json new file mode 100644 index 000000000..c2829a7b7 --- /dev/null +++ b/Tests/MockData/search-box/search-box-retrieve-minsk.json @@ -0,0 +1,53 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "coordinates": [ + 27.688183, + 53.864527 + ], + "type": "Point" + }, + "properties": { + "name": "Минск", + "mapbox_id": "dXJuOm1ieHBsYzpDWWds", + "feature_type": "place", + "place_formatted": "Minsk, Belarus", + "context": { + "country": { + "id": "dXJuOm1ieHBsYzpJaVU", + "name": "Belarus", + "country_code": "BY", + "country_code_alpha_3": "BLR" + }, + "region": { + "id": "dXJuOm1ieHBsYzo1Q1U", + "name": "Minsk", + "region_code": "HM", + "region_code_full": "BY-HM" + }, + "place": { + "id": "dXJuOm1ieHBsYzpDWWds", + "name": "Минск" + } + }, + "coordinates": { + "latitude": 53.864527, + "longitude": 27.688183 + }, + "bbox": [ + 27.019187, + 53.625823, + 27.96249, + 54.254909 + ], + "language": "en", + "maki": "marker", + "metadata": {} + } + } + ], + "attribution": "© 2023 Mapbox and its suppliers. All rights reserved. Use of this data is subject to the Mapbox Terms of Service. (https://www.mapbox.com/about/maps/)" +} diff --git a/Tests/MockData/search-box/search-box-suggestions-minsk.json b/Tests/MockData/search-box/search-box-suggestions-minsk.json new file mode 100644 index 000000000..9dac26784 --- /dev/null +++ b/Tests/MockData/search-box/search-box-suggestions-minsk.json @@ -0,0 +1,408 @@ +{ + "suggestions": [ + { + "name": "Minsk", + "mapbox_id": "dXJuOm1ieHBsYzpDWWds", + "feature_type": "place", + "place_formatted": "Minsk, Belarus", + "context": { + "country": { + "id": "dXJuOm1ieHBsYzpJaVU", + "name": "Belarus", + "country_code": "BY", + "country_code_alpha_3": "BLR" + }, + "region": { + "id": "dXJuOm1ieHBsYzo1Q1U", + "name": "Minsk", + "region_code": "HM", + "region_code_full": "BY-HM" + } + }, + "language": "en", + "maki": "marker", + "metadata": {}, + "distance": 9430000 + }, + { + "name": "Minsky's Pizza", + "mapbox_id": "dXJuOm1ieHJldDpHcEpoSE9ERDhHTTVoQnRmOVJLWWt3VlMxR3JyUDlIcUo2NjNHSE92MVhadVFBdUNfSVFxYlRBTDB5d3k5cTIwcXdObHdpWG1OUmhVbzBsZXBad3JORlhRYXhCb3FES3lJZUhKckdPclZoMG5uWEhjSElUYmlTU2ZqYnRWZDBZOWxiRkN1cnhkVW8wN3lGS2JsSFdIM29KelNTX2N1X1dUdG5ZeGlrczY4VzFtTk01eExiTEpwQWxRN1Q0MWwycHlubEszSTNJeVdveDhsRmptTjZ5SXFySW0tX2ctRk5GQ0l3MnBSSERrME1VTjNkQnNfMFNWeEFxdWotQ1duVDdReVBoWnQ4RTNtcEp1Ukp4MlJNbVRvdXd2TmZJNmc0clRkSjJpaEF5d0xzN2tHcjhZenBpYkJ5OHozcC01b0NJang4VGR2TElVNGZrdVlHVlZGaktnNU5kY2pEOWhkdlFZSnQ2Vm9wYWFETkdwZ25iRWk0bVhUQnNCdkZKMUQ4UGhEUW5aOHkweU82S29GV1B5WlZLSDVrcVZnWkZjYmR6T2xNcjJmWlRGcUM1QWNZRW5rVkNrVjliWFRPdFBlWWJEOG8tc25ILTlJVmtIeldVbV9fUW5iaGJYbW1oV1RjYlR6TkN4VjkwV2hBMTUzUEc5VzdoMGZiNWMtZjdLcUNQbGFDU29KRWNQSzBvLWI4Qkx3a3o4d2cyTG56VWUyWlFjbUJLR0E1cUF4NVBiVVhrYVZmdGVwVWxmUU1sekNTaUJJb3hIVWxSY1l3TlE1WjNpZW4wN2NqMlg0VjMxR1NKdWZKVkM1QThieFJFdDk5ZUo5aHVfbHJqbDA1RTdwaGJDdlk0WXdIOTJ1SzFNczZmR21TYUVkTFRnUmQ3eVFSUWpHTWdTd01xRzJoYXlyYmlndlJOeTdKdUEwSlF4SUJRQmxpcnNQMHN6dWU5ZUIwNnlZVTFtN0ZaenVpT3hXb2ZhZUV3SDlsemJpa1daNmV0RW1tb3V5NUNydExSQlgtemc4SGRRZ0NuYkZCMnBKa3J6am0wcHBjbWdUclBjMjZTd0VwTjhnczNuUGRzdnpyQm9oZUlBSG1LWU1LWXJ4dFFOenBXbjBwdU5TUFB3eWpWWXAwVl9JWWs3bERZY2NVRVhqenhKT0QzQnZzczE1U2RHWW9lVmZ6T1U0LWdyeVN4VUVVcVV4WmNNcUlveFVERHJMNndfSHlkTUVsdnhueEdweXhXdW11enBhNUk2RmIyWERaYmZac3hYcW5mUERlekl5OE5WMkQxOXY3djlfeGFGdHVlT1BJR2NBNnBKam5iNWZjTmp4eTF1MTFjdkx0WG56YVFvQlRsUkt0aE1BUlY3RHNWSVUyTEtZc2QzZU9LbXoxQ3JNb0tWNXF4RmsxbzY5aXd2YXhYekRHZDVJdUdkN244NXJ2OVlmSkJLb0drN3FrOVNtVnhsYlBCLTR4SjFaRjNKWk9fZEJiLVhRLWhyWFUwSlEteGRSd05GMTFSZHVETEE4Q3BtTnJwR0RxZEQtVG16ZlcyMG9ueXpuVVFnWjRYWnU3RVpCMjlkTnpQQ0E2ZHZPemZzejhkNVhqN1NOQnY5eUpkQi1RVW5HODhpMnVSOEo5NlplcTVlOXl4QUVzUGNHSW0xR1ZqRzlGUV9iMUltbmU3bTV0cVpMM3VwZE9mTjQ1SzZCM1VjM1hUclhEZ3ktNW92ck9EZ2M0b0lrSzRoNjN4N2wzcTZld1ZkcmFSYWV0WXFrWmVFZmgzOQ==", + "feature_type": "brand", + "place_formatted": "Brand", + "context": {}, + "language": "en", + "brand": [ + "Minsky's Pizza" + ], + "external_ids": {} + }, + { + "name": "Paul Minsky PhD", + "mapbox_id": "dXJuOm1ieHBvaTo1NzFjMzQzMy1lNzdkLTQ3MDctODdmMi02NmZmMDg2ZDQxYTc", + "feature_type": "poi", + "address": "2006 Dwight Way Ste 101", + "full_address": "2006 Dwight Way Ste 101, Berkeley, California 94704, United States", + "place_formatted": "Berkeley, California 94704, United States", + "context": { + "country": { + "name": "United States", + "country_code": "US", + "country_code_alpha_3": "USA" + }, + "region": { + "name": "California", + "region_code": "CA", + "region_code_full": "US-CA" + }, + "postcode": { + "id": "dXJuOm1ieHBsYzpFcjN1N0E", + "name": "94704" + }, + "place": { + "id": "dXJuOm1ieHBsYzpBWW1JN0E", + "name": "Berkeley" + }, + "neighborhood": { + "id": "dXJuOm1ieHBsYzpJM0JzN0E", + "name": "South Berkeley" + }, + "address": { + "name": "2006 Dwight Way Ste 101", + "address_number": "2006", + "street_name": "dwight way" + }, + "street": { + "name": "dwight way" + } + }, + "language": "en", + "maki": "marker", + "poi_category": [ + "doctor's office", + "health services", + "services" + ], + "poi_category_ids": [ + "doctors_office", + "health_services", + "services" + ], + "external_ids": { + "foursquare": "93cba9492be84d01aeca92be", + "safegraph": "23w-223@5vg-7qm-xkf" + }, + "metadata": {}, + "distance": 15000 + }, + { + "name": "Katie Mink LAc", + "name_preferred": "Mink Katie L.Ac.", + "mapbox_id": "dXJuOm1ieHBvaTplYjY5NmFkMy0xZjNlLTRmMjAtOWJjMy1hNGM3YTYyZWQzMzA", + "feature_type": "poi", + "address": "1720 Bancroft Way", + "full_address": "1720 Bancroft Way, Berkeley, California 94703, United States", + "place_formatted": "Berkeley, California 94703, United States", + "context": { + "country": { + "name": "United States", + "country_code": "US", + "country_code_alpha_3": "USA" + }, + "region": { + "name": "California", + "region_code": "CA", + "region_code_full": "US-CA" + }, + "postcode": { + "id": "dXJuOm1ieHBsYzpFcjNPN0E", + "name": "94703" + }, + "place": { + "id": "dXJuOm1ieHBsYzpBWW1JN0E", + "name": "Berkeley" + }, + "neighborhood": { + "id": "dXJuOm1ieHBsYzpCaVFzN0E", + "name": "Central Berkeley" + }, + "address": { + "name": "1720 Bancroft Way", + "address_number": "1720", + "street_name": "bancroft way" + }, + "street": { + "name": "bancroft way" + } + }, + "language": "en", + "maki": "marker", + "poi_category": [ + "health services", + "medical practice", + "services" + ], + "poi_category_ids": [ + "health_services", + "medical_practice", + "services" + ], + "external_ids": { + "safegraph": "22y-229@5vg-7qm-ht9", + "foursquare": "336af7a8e3474eb55f971af8" + }, + "metadata": {}, + "distance": 15000 + }, + { + "name": "Minsky's Pizza", + "mapbox_id": "dXJuOm1ieHBvaTo1YzUxMzVmNy0wZjgyLTQzM2EtYjJiNC02MTI2M2JiY2UyN2E", + "feature_type": "poi", + "address": "7198 Renner Rd", + "full_address": "7198 Renner Rd, Shawnee, Kansas 66217, United States", + "place_formatted": "Shawnee, Kansas 66217, United States", + "context": { + "country": { + "name": "United States", + "country_code": "US", + "country_code_alpha_3": "USA" + }, + "region": { + "name": "Kansas", + "region_code": "KS", + "region_code_full": "US-KS" + }, + "postcode": { + "id": "dXJuOm1ieHBsYzpEWjBPN0E", + "name": "66217" + }, + "place": { + "id": "dXJuOm1ieHBsYzpFZDlvN0E", + "name": "Shawnee" + }, + "address": { + "name": "7198 Renner Rd", + "address_number": "7198", + "street_name": "renner rd" + }, + "street": { + "name": "renner rd" + } + }, + "language": "en", + "maki": "restaurant", + "poi_category": [ + "fast food restaurant", + "food", + "food and drink", + "salad bar" + ], + "poi_category_ids": [ + "fast_food", + "food", + "food_and_drink", + "salad_bar" + ], + "brand": [ + "Minsky's Pizza" + ], + "brand_id": [ + "minskys_pizza" + ], + "external_ids": { + "safegraph": "225-222@5pr-6ny-q2k", + "foursquare": "4b1efdf7f964a520982224e3" + }, + "metadata": {}, + "distance": 2400000 + }, + { + "name": "Minsky's Pizza", + "mapbox_id": "dXJuOm1ieHBvaTo4NWIwZDU2NS01M2M5LTRlNGEtOTdjNC0zMTgxMzUxMzNhNjY", + "feature_type": "poi", + "address": "2201 NW State Route 7", + "full_address": "2201 NW State Route 7, Blue Springs, Missouri 64015, United States", + "place_formatted": "Blue Springs, Missouri 64015, United States", + "context": { + "country": { + "name": "United States", + "country_code": "US", + "country_code_alpha_3": "USA" + }, + "region": { + "name": "Missouri", + "region_code": "MO", + "region_code_full": "US-MO" + }, + "postcode": { + "id": "dXJuOm1ieHBsYzpEVFN1N0E", + "name": "64015" + }, + "place": { + "id": "dXJuOm1ieHBsYzpBZVJJN0E", + "name": "Blue Springs" + }, + "address": { + "name": "2201 NW State Route 7", + "address_number": "2201", + "street_name": "nw state route 7" + }, + "street": { + "name": "nw state route 7" + } + }, + "language": "en", + "maki": "restaurant", + "poi_category": [ + "fast food restaurant", + "food", + "food and drink", + "salad bar" + ], + "poi_category_ids": [ + "fast_food", + "food", + "food_and_drink", + "salad_bar" + ], + "brand": [ + "Minsky's Pizza" + ], + "brand_id": [ + "minskys_pizza" + ], + "external_ids": { + "safegraph": "224-222@5pr-33t-btv", + "foursquare": "4b6762d9f964a520c14b2be3" + }, + "metadata": {}, + "distance": 2450000 + }, + { + "name": "Minsky's Pizza", + "mapbox_id": "dXJuOm1ieHBvaTo5ZDY5YTEwMC03YWJhLTQ3MTItOWM4OS1mZmRiNmM1OGM0MmY", + "feature_type": "poi", + "address": "10540 S Ridgeview Rd", + "full_address": "10540 S Ridgeview Rd, Olathe, Kansas 66061, United States", + "place_formatted": "Olathe, Kansas 66061, United States", + "context": { + "country": { + "name": "United States", + "country_code": "US", + "country_code_alpha_3": "USA" + }, + "region": { + "name": "Kansas", + "region_code": "KS", + "region_code_full": "US-KS" + }, + "postcode": { + "id": "dXJuOm1ieHBsYzpEWld1N0E", + "name": "66061" + }, + "place": { + "id": "dXJuOm1ieHBsYzpEbjVJN0E", + "name": "Olathe" + }, + "neighborhood": { + "id": "dXJuOm1ieHBsYzpHc1pzN0E", + "name": "North Ridgeview" + }, + "address": { + "name": "10540 S Ridgeview Rd", + "address_number": "10540", + "street_name": "s ridgeview rd" + }, + "street": { + "name": "s ridgeview rd" + } + }, + "language": "en", + "maki": "restaurant", + "poi_category": [ + "fast food restaurant", + "food", + "food and drink", + "salad bar" + ], + "poi_category_ids": [ + "fast_food", + "food", + "food_and_drink", + "salad_bar" + ], + "brand": [ + "Minsky's Pizza" + ], + "brand_id": [ + "minskys_pizza" + ], + "external_ids": { + "safegraph": "226-222@5pr-6p8-2zf", + "foursquare": "5bde4038db1d81002c9b585c" + }, + "metadata": {}, + "distance": 2400000 + }, + { + "name": "Minsk", + "mapbox_id": "dXJuOm1ieHBsYzo1Q1U", + "feature_type": "region", + "place_formatted": "Belarus", + "context": { + "country": { + "id": "dXJuOm1ieHBsYzpJaVU", + "name": "Belarus", + "country_code": "BY", + "country_code_alpha_3": "BLR" + } + }, + "language": "en", + "maki": "marker", + "metadata": {}, + "distance": 9420000 + }, + { + "name": "Minsk Region", + "mapbox_id": "dXJuOm1ieHBsYzp4Q1U", + "feature_type": "region", + "place_formatted": "Belarus", + "context": { + "country": { + "id": "dXJuOm1ieHBsYzpJaVU", + "name": "Belarus", + "country_code": "BY", + "country_code_alpha_3": "BLR" + } + }, + "language": "en", + "maki": "marker", + "metadata": {}, + "distance": 9450000 + }, + { + "name": "Mińsk County", + "mapbox_id": "dXJuOm1ieHBsYzpFZWEx", + "feature_type": "district", + "place_formatted": "Masovian Voivodeship, Poland", + "context": { + "country": { + "id": "dXJuOm1ieHBsYzpJclU", + "name": "Poland", + "country_code": "PL", + "country_code_alpha_3": "POL" + }, + "region": { + "id": "dXJuOm1ieHBsYzo1TFU", + "name": "Masovian Voivodeship", + "region_code": "14", + "region_code_full": "PL-14" + } + }, + "language": "en", + "maki": "marker", + "metadata": {}, + "distance": 9420000 + } + ], + "attribution": "© 2023 Mapbox and its suppliers. All rights reserved. Use of this data is subject to the Mapbox Terms of Service. (https://www.mapbox.com/about/maps/)" +}