diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/Runner.xcodeproj/project.pbxproj index d4c9b554903c..f80958fd9d37 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/Runner.xcodeproj/project.pbxproj @@ -31,7 +31,7 @@ B3A7FA04ABB7B84780729949 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 61A9A8623F5CA9BBC813DC6B /* Pods_Runner.framework */; }; F269303B2BB389BF00BF17C4 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = F269303A2BB389BF00BF17C4 /* assets */; }; F7151F13265D7ED70028CB91 /* GoogleMapsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */; }; - F7151F21265D7EE50028CB91 /* GoogleMapsUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */; }; + F7151F21265D7EE50028CB91 /* GoogleMapsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3351C2253008164500700458 /* GoogleMapsUITests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -70,6 +70,7 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 2A6906C62D263DE7001F8426 /* GroundOverlayControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GroundOverlayControllerTests.m; sourceTree = ""; }; 330909FE2D99B79B0077A751 /* MarkerControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MarkerControllerTests.m; sourceTree = ""; }; + 3351C2253008164500700458 /* GoogleMapsUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleMapsUITests.swift; sourceTree = ""; }; 3390B4572F33AFA60094DEB9 /* PartiallyMockedMapView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PartiallyMockedMapView.h; sourceTree = ""; }; 3390B4582F33AFA60094DEB9 /* PartiallyMockedMapView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PartiallyMockedMapView.m; sourceTree = ""; }; 3390B4592F33AFA60094DEB9 /* TestAssetProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestAssetProvider.h; sourceTree = ""; }; @@ -91,6 +92,7 @@ 6851F3552835BC180032B7C8 /* ConversionsUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConversionsUtilsTests.m; sourceTree = ""; }; 733AFAB37683A9DA7512F09C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 784666492D4C4C64000A1A5F /* FlutterFramework */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterFramework; path = Flutter/ephemeral/Packages/.packages/FlutterFramework; sourceTree = ""; }; + 78DABEA22ED26510000E7860 /* google_maps_flutter_ios */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = google_maps_flutter_ios; path = ../../ios/google_maps_flutter_ios; sourceTree = ""; }; 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; @@ -108,7 +110,6 @@ F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsTests.m; sourceTree = ""; }; F7151F14265D7ED70028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; F7151F1E265D7EE50028CB91 /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsUITests.m; sourceTree = ""; }; F7151F22265D7EE50028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ @@ -165,6 +166,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 78DABEA22ED26510000E7860 /* google_maps_flutter_ios */, 784666492D4C4C64000A1A5F /* FlutterFramework */, 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, @@ -249,7 +251,7 @@ F7151F1F265D7EE50028CB91 /* RunnerUITests */ = { isa = PBXGroup; children = ( - F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */, + 3351C2253008164500700458 /* GoogleMapsUITests.swift */, F7151F22265D7EE50028CB91 /* Info.plist */, ); path = RunnerUITests; @@ -355,7 +357,7 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; @@ -526,7 +528,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - F7151F21265D7EE50028CB91 /* GoogleMapsUITests.m in Sources */, + F7151F21265D7EE50028CB91 /* GoogleMapsUITests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -783,6 +785,7 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; TEST_TARGET_NAME = Runner; }; name = Debug; @@ -800,6 +803,7 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; TEST_TARGET_NAME = Runner; }; name = Release; @@ -846,7 +850,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerUITests/GoogleMapsUITests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerUITests/GoogleMapsUITests.m deleted file mode 100644 index cb7fbc196b40..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerUITests/GoogleMapsUITests.m +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import CoreLocation; -@import XCTest; -@import os.log; - -static const NSTimeInterval kWaitTime = 60; - -// TODO(bparrishMines): Remove once https://github.com/flutter/flutter/issues/154641 is fixed. -static const BOOL skipFor154641 = YES; - -@interface GoogleMapsUITests : XCTestCase -@property(nonatomic, strong) XCUIApplication *app; -@end - -@implementation GoogleMapsUITests - -- (void)setUp { - self.continueAfterFailure = NO; - - self.app = [[XCUIApplication alloc] init]; - [self.app launch]; - - [self - addUIInterruptionMonitorWithDescription:@"Permission popups" - handler:^BOOL(XCUIElement *_Nonnull interruptingElement) { - if (@available(iOS 14, *)) { - XCUIElement *locationPermission = - interruptingElement.buttons[@"Allow While Using App"]; - if (![locationPermission - waitForExistenceWithTimeout:kWaitTime]) { - XCTFail(@"Failed due to not able to find " - @"locationPermission button"); - } - [locationPermission tap]; - - } else { - XCUIElement *allow = - interruptingElement.buttons[@"Allow"]; - if (![allow waitForExistenceWithTimeout:kWaitTime]) { - XCTFail(@"Failed due to not able to find Allow button"); - } - [allow tap]; - } - return YES; - }]; -} - -- (void)testUserInterface { - XCTSkipIf(skipFor154641); - - XCUIApplication *app = self.app; - XCUIElement *userInteface = app.staticTexts[@"User interface"]; - if (![userInteface waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find User interface"); - } - [userInteface tap]; - - XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; - if (![platformView waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find platform view"); - } - - // There is a known bug where the permission popups interruption won't get fired until a tap - // happened in the app. We expect a permission popup so we do a tap here. - // iOS 16 has a bug where if the app itself is directly tapped: [app tap], the first button - // (disable compass) in the app is also tapped, so instead we tap a arbitrary location in the app - // instead. - XCUICoordinate *coordinate = [app coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; - [coordinate tap]; - XCUIElement *compass = app.buttons[@"disable compass"]; - if (![compass waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find disable compass button"); - } - - [self forceTap:compass]; -} - -- (void)testMapCoordinatesPage { - XCTSkipIf(skipFor154641); - - XCUIApplication *app = self.app; - XCUIElement *mapCoordinates = app.staticTexts[@"Map coordinates"]; - if (![mapCoordinates waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'Map coordinates''"); - } - [mapCoordinates tap]; - - XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; - if (![platformView waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find platform view"); - } - - XCUIElement *titleBar = app.otherElements[@"Map coordinates"]; - if (![titleBar waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find title bar"); - } - - NSPredicate *visibleRegionPredicate = - [NSPredicate predicateWithFormat:@"label BEGINSWITH 'VisibleRegion'"]; - XCUIElement *visibleRegionText = - [app.staticTexts elementMatchingPredicate:visibleRegionPredicate]; - if (![visibleRegionText waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find Visible Region label'"); - } - - // Validate visible region does not change when scrolled under safe areas. - // https://github.com/flutter/flutter/issues/107913 - - // Example -33.79495661816674, 151.313996873796 - CLLocationCoordinate2D originalNortheast; - // Example -33.90900557679571, 151.10800322145224 - CLLocationCoordinate2D originalSouthwest; - [self validateVisibleRegion:visibleRegionText.label - northeast:&originalNortheast - southwest:&originalSouthwest]; - XCTAssertGreaterThan(originalNortheast.latitude, originalSouthwest.latitude); - XCTAssertGreaterThan(originalNortheast.longitude, originalSouthwest.longitude); - - XCTAssertLessThan(originalNortheast.latitude, 0); - XCTAssertLessThan(originalSouthwest.latitude, 0); - XCTAssertGreaterThan(originalNortheast.longitude, 0); - XCTAssertGreaterThan(originalSouthwest.longitude, 0); - - // Drag the map upward to under the title bar. - [platformView pressForDuration:0 thenDragToElement:titleBar]; - - CLLocationCoordinate2D draggedNortheast; - CLLocationCoordinate2D draggedSouthwest; - [self validateVisibleRegion:visibleRegionText.label - northeast:&draggedNortheast - southwest:&draggedSouthwest]; - XCTAssertEqual(originalNortheast.latitude, draggedNortheast.latitude); - XCTAssertEqual(originalNortheast.longitude, draggedNortheast.longitude); - XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); - XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); -} - -- (void)validateVisibleRegion:(NSString *)label - northeast:(CLLocationCoordinate2D *)northeast - southwest:(CLLocationCoordinate2D *)southwest { - // String will be "VisibleRegion:\nnortheast: LatLng(-33.79495661816674, - // 151.313996873796),\nsouthwest: LatLng(-33.90900557679571, 151.10800322145224)" - NSScanner *scan = [NSScanner scannerWithString:label]; - - // northeast - [scan scanString:@"VisibleRegion:\nnortheast: LatLng(" intoString:NULL]; - double northeastLatitude; - [scan scanDouble:&northeastLatitude]; - [scan scanString:@", " intoString:NULL]; - XCTAssertNotEqual(northeastLatitude, 0); - double northeastLongitude; - [scan scanDouble:&northeastLongitude]; - XCTAssertNotEqual(northeastLongitude, 0); - - [scan scanString:@"),\nsouthwest: LatLng(" intoString:NULL]; - double southwestLatitude; - [scan scanDouble:&southwestLatitude]; - XCTAssertNotEqual(southwestLatitude, 0); - [scan scanString:@", " intoString:NULL]; - double southwestLongitude; - [scan scanDouble:&southwestLongitude]; - XCTAssertNotEqual(southwestLongitude, 0); - *northeast = CLLocationCoordinate2DMake(northeastLatitude, northeastLongitude); - *southwest = CLLocationCoordinate2DMake(southwestLatitude, southwestLongitude); -} - -- (void)testMapClickPage { - XCTSkipIf(skipFor154641); - - XCUIApplication *app = self.app; - XCUIElement *mapClick = app.staticTexts[@"Map click"]; - if (![mapClick waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'Map click''"); - } - [mapClick tap]; - - XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; - if (![platformView waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find platform view"); - } - - [platformView tap]; - - XCUIElement *tapped = app.staticTexts[@"Tapped"]; - if (![tapped waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'tapped''"); - } - - [platformView pressForDuration:5.0]; - - XCUIElement *longPressed = app.staticTexts[@"Long pressed"]; - if (![longPressed waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'longPressed''"); - } -} - -- (void)forceTap:(XCUIElement *)button { - // iOS 16 introduced a bug where hittable is NO for buttons. We force hit the location of the - // button if that is the case. It is likely similar to - // https://github.com/flutter/flutter/issues/113377. - if (button.isHittable) { - [button tap]; - return; - } - XCUICoordinate *coordinate = [button coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; - [coordinate tap]; -} - -- (void)testMarkerDraggingCallbacks { - XCTSkipIf(skipFor154641); - - XCUIApplication *application = [[XCUIApplication alloc] init]; - [application launch]; - XCUIElement *placeMarkerButton = application.staticTexts[@"Place marker"]; - if (![placeMarkerButton waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the Place marker button."); - } - [placeMarkerButton tap]; - - XCUIElement *Add = application.buttons[@"Add"]; - if (![Add waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the Add button."); - } - [Add tap]; - - XCUIElement *marker = application.buttons[@"marker_id_1"]; - if (![marker waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the marker."); - } - [marker tap]; - - XCUIElement *toggleDraggable = application.buttons[@"toggle draggable"]; - if (![toggleDraggable waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the toggle draggable."); - } - [toggleDraggable tap]; - - // Drag marker to center - [marker pressForDuration:5 thenDragToElement:application]; - - NSPredicate *predicateDragStart = - [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragStart"]; - NSPredicate *predicateDrag = - [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDrag called"]; - NSPredicate *predicateDragEnd = - [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragEnd"]; - - XCUIElement *dragStart = [application.staticTexts matchingPredicate:predicateDragStart].element; - if (![dragStart waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the _onMarkerDragStart."); - } - XCTAssertTrue(dragStart.exists); - - XCUIElement *drag = [application.staticTexts matchingPredicate:predicateDrag].element; - if (![drag waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the _onMarkerDrag."); - } - XCTAssertTrue(drag.exists); - - XCUIElement *dragEnd = [application.staticTexts matchingPredicate:predicateDragEnd].element; - if (![dragEnd waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the _onMarkerDragEnd."); - } - XCTAssertTrue(dragEnd.exists); -} - -@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerUITests/GoogleMapsUITests.swift b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerUITests/GoogleMapsUITests.swift new file mode 100644 index 000000000000..16c2ccd5db8b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerUITests/GoogleMapsUITests.swift @@ -0,0 +1,265 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import CoreLocation +import XCTest +import os.log + +private let kWaitTime: TimeInterval = 60 + +class GoogleMapsUITests: XCTestCase { + var app: XCUIApplication! + + override func setUp() { + super.setUp() + continueAfterFailure = false + + app = XCUIApplication() + app.launch() + + addUIInterruptionMonitor(withDescription: "Permission popups") { interruptingElement in + if #available(iOS 14, *) { + let locationPermission = interruptingElement.buttons["Allow While Using App"] + if !locationPermission.waitForExistence(timeout: kWaitTime) { + XCTFail("Failed due to not able to find locationPermission button") + } + locationPermission.tap() + } else { + let allow = interruptingElement.buttons["Allow"] + if !allow.waitForExistence(timeout: kWaitTime) { + XCTFail("Failed due to not able to find Allow button") + } + allow.tap() + } + return true + } + } + + func testUserInterface() throws { + let userInterface = app.buttons["User interface"] + if !userInterface.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find User interface") + } + userInterface.tap() + + let platformView = app.otherElements["platform_view[0]"] + if !platformView.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find platform view") + } + + // There is a known bug where the permission popups interruption won't get fired until a tap + // happened in the app. We expect a permission popup so we do a tap here. + // iOS 16 has a bug where if the app itself is directly tapped: [app tap], the first button + // (disable compass) in the app is also tapped, so instead we tap a arbitrary location in the app + // instead. + let coordinate = app.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)) + coordinate.tap() + let compass = app.buttons["disable compass"] + if !compass.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find disable compass button") + } + + forceTap(compass) + } + + func testMapCoordinatesPage() throws { + let mapCoordinates = app.buttons["Map coordinates"] + if !mapCoordinates.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'Map coordinates'") + } + mapCoordinates.tap() + + let platformView = app.otherElements["platform_view[0]"] + if !platformView.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find platform view") + } + + let titleBar = app.staticTexts["Map coordinates"] + if !titleBar.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find title bar") + } + + let visibleRegionPredicate = NSPredicate(format: "label BEGINSWITH 'VisibleRegion'") + let visibleRegionText = app.staticTexts.element(matching: visibleRegionPredicate) + if !visibleRegionText.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find Visible Region label") + } + + // Validate visible region does not change when scrolled under safe areas. + // https://github.com/flutter/flutter/issues/107913 + + // Example -33.79495661816674, 151.313996873796 + let (originalNortheast, originalSouthwest) = try XCTUnwrap( + validateVisibleRegion(visibleRegionText.label) + ) + XCTAssertGreaterThan(originalNortheast.latitude, originalSouthwest.latitude) + XCTAssertGreaterThan(originalNortheast.longitude, originalSouthwest.longitude) + + XCTAssertLessThan(originalNortheast.latitude, 0) + XCTAssertLessThan(originalSouthwest.latitude, 0) + XCTAssertGreaterThan(originalNortheast.longitude, 0) + XCTAssertGreaterThan(originalSouthwest.longitude, 0) + + // Drag the map upward to under the title bar. + platformView.press(forDuration: 0, thenDragTo: titleBar) + + let (draggedNortheast, draggedSouthwest) = try XCTUnwrap( + validateVisibleRegion(visibleRegionText.label) + ) + XCTAssertEqual(originalNortheast.latitude, draggedNortheast.latitude) + XCTAssertEqual(originalNortheast.longitude, draggedNortheast.longitude) + XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude) + XCTAssertEqual(originalSouthwest.longitude, draggedSouthwest.longitude) + } + + func validateVisibleRegion( + _ label: String + ) -> (northeast: CLLocationCoordinate2D, southwest: CLLocationCoordinate2D)? { + // String will be "VisibleRegion:\nnortheast: LatLng(-33.79495661816674, + // 151.313996873796),\nsouthwest: LatLng(-33.90900557679571, 151.10800322145224)" + let scan = Scanner(string: label) + + // northeast + _ = scan.scanString("VisibleRegion:\nnortheast: LatLng(") + guard let northeastLatitude = scan.scanDouble() else { + XCTFail("Failed to scan northeastLatitude") + return nil + } + _ = scan.scanString(", ") + XCTAssertNotEqual(northeastLatitude, 0) + guard let northeastLongitude = scan.scanDouble() else { + XCTFail("Failed to scan northeastLongitude") + return nil + } + XCTAssertNotEqual(northeastLongitude, 0) + + _ = scan.scanString("),\nsouthwest: LatLng(") + guard let southwestLatitude = scan.scanDouble() else { + XCTFail("Failed to scan southwestLatitude") + return nil + } + XCTAssertNotEqual(southwestLatitude, 0) + _ = scan.scanString(", ") + guard let southwestLongitude = scan.scanDouble() else { + XCTFail("Failed to scan southwestLongitude") + return nil + } + XCTAssertNotEqual(southwestLongitude, 0) + + return ( + CLLocationCoordinate2D(latitude: northeastLatitude, longitude: northeastLongitude), + CLLocationCoordinate2D(latitude: southwestLatitude, longitude: southwestLongitude) + ) + } + + func testMapClickPage() throws { + let mapClick = app.buttons["Map click"] + if !mapClick.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'Map click'") + } + mapClick.tap() + + let platformView = app.otherElements["platform_view[0]"] + if !platformView.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find platform view") + } + + platformView.tap() + + let tapped = app.staticTexts["Tapped"] + if !tapped.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'tapped'") + } + + platformView.press(forDuration: 5.0) + + let longPressed = app.staticTexts["Long pressed"] + if !longPressed.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'longPressed'") + } + } + + func forceTap(_ button: XCUIElement) { + // iOS 16 introduced a bug where hittable is NO for buttons. We force hit the location of the + // button if that is the case. It is likely similar to + // https://github.com/flutter/flutter/issues/113377. + if button.isHittable { + button.tap() + return + } + let coordinate = button.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)) + coordinate.tap() + } + + func testMarkerDraggingCallbacks() throws { + let application = XCUIApplication() + application.launch() + let placeMarkerButton = application.buttons["Place marker"] + if !placeMarkerButton.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the Place marker button.") + } + placeMarkerButton.tap() + + let add = application.buttons["Add"] + if !add.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the Add button.") + } + add.tap() + + let marker = application.buttons["marker_id_1"] + if !marker.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the marker.") + } + marker.tap() + + let toggleDraggable = application.buttons["toggle draggable"] + if !toggleDraggable.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the toggle draggable.") + } + toggleDraggable.tap() + + // Drag marker to center + marker.press(forDuration: 5, thenDragTo: application) + + let predicateDragStart = NSPredicate(format: "label CONTAINS[c] %@", "_onMarkerDragStart") + let predicateDrag = NSPredicate(format: "label CONTAINS[c] %@", "_onMarkerDrag called") + let predicateDragEnd = NSPredicate(format: "label CONTAINS[c] %@", "_onMarkerDragEnd") + + let dragStart = application.staticTexts.matching(predicateDragStart).element + if !dragStart.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the _onMarkerDragStart.") + } + XCTAssertTrue(dragStart.exists) + + let drag = application.staticTexts.matching(predicateDrag).element + if !drag.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the _onMarkerDrag.") + } + XCTAssertTrue(drag.exists) + + let dragEnd = application.staticTexts.matching(predicateDragEnd).element + if !dragEnd.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the _onMarkerDragEnd.") + } + XCTAssertTrue(dragEnd.exists) + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj index f76391a39586..da9894077ee8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj @@ -29,7 +29,7 @@ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; F269303B2BB389BF00BF17C4 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = F269303A2BB389BF00BF17C4 /* assets */; }; F7151F13265D7ED70028CB91 /* GoogleMapsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */; }; - F7151F21265D7EE50028CB91 /* GoogleMapsUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */; }; + F7151F21265D7EE50028CB91 /* GoogleMapsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3351C2253008164500700458 /* GoogleMapsUITests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -68,6 +68,7 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 2A6906C62D263DE7001F8426 /* GroundOverlayControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GroundOverlayControllerTests.m; sourceTree = ""; }; 330909FE2D99B79B0077A751 /* MarkerControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MarkerControllerTests.m; sourceTree = ""; }; + 3351C2253008164500700458 /* GoogleMapsUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleMapsUITests.swift; sourceTree = ""; }; 3390B4572F33AFA60094DEB9 /* PartiallyMockedMapView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PartiallyMockedMapView.h; sourceTree = ""; }; 3390B4582F33AFA60094DEB9 /* PartiallyMockedMapView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PartiallyMockedMapView.m; sourceTree = ""; }; 3390B4592F33AFA60094DEB9 /* TestAssetProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestAssetProvider.h; sourceTree = ""; }; @@ -101,7 +102,6 @@ F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsTests.m; sourceTree = ""; }; F7151F14265D7ED70028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; F7151F1E265D7EE50028CB91 /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsUITests.m; sourceTree = ""; }; F7151F22265D7EE50028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ @@ -219,7 +219,7 @@ F7151F1F265D7EE50028CB91 /* RunnerUITests */ = { isa = PBXGroup; children = ( - F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */, + 3351C2253008164500700458 /* GoogleMapsUITests.swift */, F7151F22265D7EE50028CB91 /* Info.plist */, ); path = RunnerUITests; @@ -322,7 +322,7 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; @@ -433,7 +433,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - F7151F21265D7EE50028CB91 /* GoogleMapsUITests.m in Sources */, + F7151F21265D7EE50028CB91 /* GoogleMapsUITests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -686,6 +686,7 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; TEST_TARGET_NAME = Runner; }; name = Debug; @@ -703,6 +704,7 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; TEST_TARGET_NAME = Runner; }; name = Release; @@ -749,7 +751,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/GoogleMapsUITests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/GoogleMapsUITests.m deleted file mode 100644 index cb7fbc196b40..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/GoogleMapsUITests.m +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import CoreLocation; -@import XCTest; -@import os.log; - -static const NSTimeInterval kWaitTime = 60; - -// TODO(bparrishMines): Remove once https://github.com/flutter/flutter/issues/154641 is fixed. -static const BOOL skipFor154641 = YES; - -@interface GoogleMapsUITests : XCTestCase -@property(nonatomic, strong) XCUIApplication *app; -@end - -@implementation GoogleMapsUITests - -- (void)setUp { - self.continueAfterFailure = NO; - - self.app = [[XCUIApplication alloc] init]; - [self.app launch]; - - [self - addUIInterruptionMonitorWithDescription:@"Permission popups" - handler:^BOOL(XCUIElement *_Nonnull interruptingElement) { - if (@available(iOS 14, *)) { - XCUIElement *locationPermission = - interruptingElement.buttons[@"Allow While Using App"]; - if (![locationPermission - waitForExistenceWithTimeout:kWaitTime]) { - XCTFail(@"Failed due to not able to find " - @"locationPermission button"); - } - [locationPermission tap]; - - } else { - XCUIElement *allow = - interruptingElement.buttons[@"Allow"]; - if (![allow waitForExistenceWithTimeout:kWaitTime]) { - XCTFail(@"Failed due to not able to find Allow button"); - } - [allow tap]; - } - return YES; - }]; -} - -- (void)testUserInterface { - XCTSkipIf(skipFor154641); - - XCUIApplication *app = self.app; - XCUIElement *userInteface = app.staticTexts[@"User interface"]; - if (![userInteface waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find User interface"); - } - [userInteface tap]; - - XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; - if (![platformView waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find platform view"); - } - - // There is a known bug where the permission popups interruption won't get fired until a tap - // happened in the app. We expect a permission popup so we do a tap here. - // iOS 16 has a bug where if the app itself is directly tapped: [app tap], the first button - // (disable compass) in the app is also tapped, so instead we tap a arbitrary location in the app - // instead. - XCUICoordinate *coordinate = [app coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; - [coordinate tap]; - XCUIElement *compass = app.buttons[@"disable compass"]; - if (![compass waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find disable compass button"); - } - - [self forceTap:compass]; -} - -- (void)testMapCoordinatesPage { - XCTSkipIf(skipFor154641); - - XCUIApplication *app = self.app; - XCUIElement *mapCoordinates = app.staticTexts[@"Map coordinates"]; - if (![mapCoordinates waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'Map coordinates''"); - } - [mapCoordinates tap]; - - XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; - if (![platformView waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find platform view"); - } - - XCUIElement *titleBar = app.otherElements[@"Map coordinates"]; - if (![titleBar waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find title bar"); - } - - NSPredicate *visibleRegionPredicate = - [NSPredicate predicateWithFormat:@"label BEGINSWITH 'VisibleRegion'"]; - XCUIElement *visibleRegionText = - [app.staticTexts elementMatchingPredicate:visibleRegionPredicate]; - if (![visibleRegionText waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find Visible Region label'"); - } - - // Validate visible region does not change when scrolled under safe areas. - // https://github.com/flutter/flutter/issues/107913 - - // Example -33.79495661816674, 151.313996873796 - CLLocationCoordinate2D originalNortheast; - // Example -33.90900557679571, 151.10800322145224 - CLLocationCoordinate2D originalSouthwest; - [self validateVisibleRegion:visibleRegionText.label - northeast:&originalNortheast - southwest:&originalSouthwest]; - XCTAssertGreaterThan(originalNortheast.latitude, originalSouthwest.latitude); - XCTAssertGreaterThan(originalNortheast.longitude, originalSouthwest.longitude); - - XCTAssertLessThan(originalNortheast.latitude, 0); - XCTAssertLessThan(originalSouthwest.latitude, 0); - XCTAssertGreaterThan(originalNortheast.longitude, 0); - XCTAssertGreaterThan(originalSouthwest.longitude, 0); - - // Drag the map upward to under the title bar. - [platformView pressForDuration:0 thenDragToElement:titleBar]; - - CLLocationCoordinate2D draggedNortheast; - CLLocationCoordinate2D draggedSouthwest; - [self validateVisibleRegion:visibleRegionText.label - northeast:&draggedNortheast - southwest:&draggedSouthwest]; - XCTAssertEqual(originalNortheast.latitude, draggedNortheast.latitude); - XCTAssertEqual(originalNortheast.longitude, draggedNortheast.longitude); - XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); - XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); -} - -- (void)validateVisibleRegion:(NSString *)label - northeast:(CLLocationCoordinate2D *)northeast - southwest:(CLLocationCoordinate2D *)southwest { - // String will be "VisibleRegion:\nnortheast: LatLng(-33.79495661816674, - // 151.313996873796),\nsouthwest: LatLng(-33.90900557679571, 151.10800322145224)" - NSScanner *scan = [NSScanner scannerWithString:label]; - - // northeast - [scan scanString:@"VisibleRegion:\nnortheast: LatLng(" intoString:NULL]; - double northeastLatitude; - [scan scanDouble:&northeastLatitude]; - [scan scanString:@", " intoString:NULL]; - XCTAssertNotEqual(northeastLatitude, 0); - double northeastLongitude; - [scan scanDouble:&northeastLongitude]; - XCTAssertNotEqual(northeastLongitude, 0); - - [scan scanString:@"),\nsouthwest: LatLng(" intoString:NULL]; - double southwestLatitude; - [scan scanDouble:&southwestLatitude]; - XCTAssertNotEqual(southwestLatitude, 0); - [scan scanString:@", " intoString:NULL]; - double southwestLongitude; - [scan scanDouble:&southwestLongitude]; - XCTAssertNotEqual(southwestLongitude, 0); - *northeast = CLLocationCoordinate2DMake(northeastLatitude, northeastLongitude); - *southwest = CLLocationCoordinate2DMake(southwestLatitude, southwestLongitude); -} - -- (void)testMapClickPage { - XCTSkipIf(skipFor154641); - - XCUIApplication *app = self.app; - XCUIElement *mapClick = app.staticTexts[@"Map click"]; - if (![mapClick waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'Map click''"); - } - [mapClick tap]; - - XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; - if (![platformView waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find platform view"); - } - - [platformView tap]; - - XCUIElement *tapped = app.staticTexts[@"Tapped"]; - if (![tapped waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'tapped''"); - } - - [platformView pressForDuration:5.0]; - - XCUIElement *longPressed = app.staticTexts[@"Long pressed"]; - if (![longPressed waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'longPressed''"); - } -} - -- (void)forceTap:(XCUIElement *)button { - // iOS 16 introduced a bug where hittable is NO for buttons. We force hit the location of the - // button if that is the case. It is likely similar to - // https://github.com/flutter/flutter/issues/113377. - if (button.isHittable) { - [button tap]; - return; - } - XCUICoordinate *coordinate = [button coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; - [coordinate tap]; -} - -- (void)testMarkerDraggingCallbacks { - XCTSkipIf(skipFor154641); - - XCUIApplication *application = [[XCUIApplication alloc] init]; - [application launch]; - XCUIElement *placeMarkerButton = application.staticTexts[@"Place marker"]; - if (![placeMarkerButton waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the Place marker button."); - } - [placeMarkerButton tap]; - - XCUIElement *Add = application.buttons[@"Add"]; - if (![Add waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the Add button."); - } - [Add tap]; - - XCUIElement *marker = application.buttons[@"marker_id_1"]; - if (![marker waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the marker."); - } - [marker tap]; - - XCUIElement *toggleDraggable = application.buttons[@"toggle draggable"]; - if (![toggleDraggable waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the toggle draggable."); - } - [toggleDraggable tap]; - - // Drag marker to center - [marker pressForDuration:5 thenDragToElement:application]; - - NSPredicate *predicateDragStart = - [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragStart"]; - NSPredicate *predicateDrag = - [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDrag called"]; - NSPredicate *predicateDragEnd = - [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragEnd"]; - - XCUIElement *dragStart = [application.staticTexts matchingPredicate:predicateDragStart].element; - if (![dragStart waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the _onMarkerDragStart."); - } - XCTAssertTrue(dragStart.exists); - - XCUIElement *drag = [application.staticTexts matchingPredicate:predicateDrag].element; - if (![drag waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the _onMarkerDrag."); - } - XCTAssertTrue(drag.exists); - - XCUIElement *dragEnd = [application.staticTexts matchingPredicate:predicateDragEnd].element; - if (![dragEnd waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the _onMarkerDragEnd."); - } - XCTAssertTrue(dragEnd.exists); -} - -@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/GoogleMapsUITests.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/GoogleMapsUITests.swift new file mode 100644 index 000000000000..16c2ccd5db8b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/GoogleMapsUITests.swift @@ -0,0 +1,265 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import CoreLocation +import XCTest +import os.log + +private let kWaitTime: TimeInterval = 60 + +class GoogleMapsUITests: XCTestCase { + var app: XCUIApplication! + + override func setUp() { + super.setUp() + continueAfterFailure = false + + app = XCUIApplication() + app.launch() + + addUIInterruptionMonitor(withDescription: "Permission popups") { interruptingElement in + if #available(iOS 14, *) { + let locationPermission = interruptingElement.buttons["Allow While Using App"] + if !locationPermission.waitForExistence(timeout: kWaitTime) { + XCTFail("Failed due to not able to find locationPermission button") + } + locationPermission.tap() + } else { + let allow = interruptingElement.buttons["Allow"] + if !allow.waitForExistence(timeout: kWaitTime) { + XCTFail("Failed due to not able to find Allow button") + } + allow.tap() + } + return true + } + } + + func testUserInterface() throws { + let userInterface = app.buttons["User interface"] + if !userInterface.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find User interface") + } + userInterface.tap() + + let platformView = app.otherElements["platform_view[0]"] + if !platformView.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find platform view") + } + + // There is a known bug where the permission popups interruption won't get fired until a tap + // happened in the app. We expect a permission popup so we do a tap here. + // iOS 16 has a bug where if the app itself is directly tapped: [app tap], the first button + // (disable compass) in the app is also tapped, so instead we tap a arbitrary location in the app + // instead. + let coordinate = app.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)) + coordinate.tap() + let compass = app.buttons["disable compass"] + if !compass.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find disable compass button") + } + + forceTap(compass) + } + + func testMapCoordinatesPage() throws { + let mapCoordinates = app.buttons["Map coordinates"] + if !mapCoordinates.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'Map coordinates'") + } + mapCoordinates.tap() + + let platformView = app.otherElements["platform_view[0]"] + if !platformView.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find platform view") + } + + let titleBar = app.staticTexts["Map coordinates"] + if !titleBar.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find title bar") + } + + let visibleRegionPredicate = NSPredicate(format: "label BEGINSWITH 'VisibleRegion'") + let visibleRegionText = app.staticTexts.element(matching: visibleRegionPredicate) + if !visibleRegionText.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find Visible Region label") + } + + // Validate visible region does not change when scrolled under safe areas. + // https://github.com/flutter/flutter/issues/107913 + + // Example -33.79495661816674, 151.313996873796 + let (originalNortheast, originalSouthwest) = try XCTUnwrap( + validateVisibleRegion(visibleRegionText.label) + ) + XCTAssertGreaterThan(originalNortheast.latitude, originalSouthwest.latitude) + XCTAssertGreaterThan(originalNortheast.longitude, originalSouthwest.longitude) + + XCTAssertLessThan(originalNortheast.latitude, 0) + XCTAssertLessThan(originalSouthwest.latitude, 0) + XCTAssertGreaterThan(originalNortheast.longitude, 0) + XCTAssertGreaterThan(originalSouthwest.longitude, 0) + + // Drag the map upward to under the title bar. + platformView.press(forDuration: 0, thenDragTo: titleBar) + + let (draggedNortheast, draggedSouthwest) = try XCTUnwrap( + validateVisibleRegion(visibleRegionText.label) + ) + XCTAssertEqual(originalNortheast.latitude, draggedNortheast.latitude) + XCTAssertEqual(originalNortheast.longitude, draggedNortheast.longitude) + XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude) + XCTAssertEqual(originalSouthwest.longitude, draggedSouthwest.longitude) + } + + func validateVisibleRegion( + _ label: String + ) -> (northeast: CLLocationCoordinate2D, southwest: CLLocationCoordinate2D)? { + // String will be "VisibleRegion:\nnortheast: LatLng(-33.79495661816674, + // 151.313996873796),\nsouthwest: LatLng(-33.90900557679571, 151.10800322145224)" + let scan = Scanner(string: label) + + // northeast + _ = scan.scanString("VisibleRegion:\nnortheast: LatLng(") + guard let northeastLatitude = scan.scanDouble() else { + XCTFail("Failed to scan northeastLatitude") + return nil + } + _ = scan.scanString(", ") + XCTAssertNotEqual(northeastLatitude, 0) + guard let northeastLongitude = scan.scanDouble() else { + XCTFail("Failed to scan northeastLongitude") + return nil + } + XCTAssertNotEqual(northeastLongitude, 0) + + _ = scan.scanString("),\nsouthwest: LatLng(") + guard let southwestLatitude = scan.scanDouble() else { + XCTFail("Failed to scan southwestLatitude") + return nil + } + XCTAssertNotEqual(southwestLatitude, 0) + _ = scan.scanString(", ") + guard let southwestLongitude = scan.scanDouble() else { + XCTFail("Failed to scan southwestLongitude") + return nil + } + XCTAssertNotEqual(southwestLongitude, 0) + + return ( + CLLocationCoordinate2D(latitude: northeastLatitude, longitude: northeastLongitude), + CLLocationCoordinate2D(latitude: southwestLatitude, longitude: southwestLongitude) + ) + } + + func testMapClickPage() throws { + let mapClick = app.buttons["Map click"] + if !mapClick.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'Map click'") + } + mapClick.tap() + + let platformView = app.otherElements["platform_view[0]"] + if !platformView.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find platform view") + } + + platformView.tap() + + let tapped = app.staticTexts["Tapped"] + if !tapped.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'tapped'") + } + + platformView.press(forDuration: 5.0) + + let longPressed = app.staticTexts["Long pressed"] + if !longPressed.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'longPressed'") + } + } + + func forceTap(_ button: XCUIElement) { + // iOS 16 introduced a bug where hittable is NO for buttons. We force hit the location of the + // button if that is the case. It is likely similar to + // https://github.com/flutter/flutter/issues/113377. + if button.isHittable { + button.tap() + return + } + let coordinate = button.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)) + coordinate.tap() + } + + func testMarkerDraggingCallbacks() throws { + let application = XCUIApplication() + application.launch() + let placeMarkerButton = application.buttons["Place marker"] + if !placeMarkerButton.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the Place marker button.") + } + placeMarkerButton.tap() + + let add = application.buttons["Add"] + if !add.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the Add button.") + } + add.tap() + + let marker = application.buttons["marker_id_1"] + if !marker.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the marker.") + } + marker.tap() + + let toggleDraggable = application.buttons["toggle draggable"] + if !toggleDraggable.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the toggle draggable.") + } + toggleDraggable.tap() + + // Drag marker to center + marker.press(forDuration: 5, thenDragTo: application) + + let predicateDragStart = NSPredicate(format: "label CONTAINS[c] %@", "_onMarkerDragStart") + let predicateDrag = NSPredicate(format: "label CONTAINS[c] %@", "_onMarkerDrag called") + let predicateDragEnd = NSPredicate(format: "label CONTAINS[c] %@", "_onMarkerDragEnd") + + let dragStart = application.staticTexts.matching(predicateDragStart).element + if !dragStart.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the _onMarkerDragStart.") + } + XCTAssertTrue(dragStart.exists) + + let drag = application.staticTexts.matching(predicateDrag).element + if !drag.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the _onMarkerDrag.") + } + XCTAssertTrue(drag.exists) + + let dragEnd = application.staticTexts.matching(predicateDragEnd).element + if !dragEnd.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the _onMarkerDragEnd.") + } + XCTAssertTrue(dragEnd.exists) + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.pbxproj index 5c2bb451d25b..f566fb8c562d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.pbxproj @@ -29,7 +29,7 @@ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; F269303B2BB389BF00BF17C4 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = F269303A2BB389BF00BF17C4 /* assets */; }; F7151F13265D7ED70028CB91 /* GoogleMapsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */; }; - F7151F21265D7EE50028CB91 /* GoogleMapsUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */; }; + F7151F21265D7EE50028CB91 /* GoogleMapsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3351C2253008164500700458 /* GoogleMapsUITests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -68,6 +68,7 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 2A6906C62D263DE7001F8426 /* GroundOverlayControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GroundOverlayControllerTests.m; sourceTree = ""; }; 330909FE2D99B79B0077A751 /* MarkerControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MarkerControllerTests.m; sourceTree = ""; }; + 3351C2253008164500700458 /* GoogleMapsUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleMapsUITests.swift; sourceTree = ""; }; 3390B4572F33AFA60094DEB9 /* PartiallyMockedMapView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PartiallyMockedMapView.h; sourceTree = ""; }; 3390B4582F33AFA60094DEB9 /* PartiallyMockedMapView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PartiallyMockedMapView.m; sourceTree = ""; }; 3390B4592F33AFA60094DEB9 /* TestAssetProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestAssetProvider.h; sourceTree = ""; }; @@ -101,7 +102,6 @@ F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsTests.m; sourceTree = ""; }; F7151F14265D7ED70028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; F7151F1E265D7EE50028CB91 /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsUITests.m; sourceTree = ""; }; F7151F22265D7EE50028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ @@ -219,7 +219,7 @@ F7151F1F265D7EE50028CB91 /* RunnerUITests */ = { isa = PBXGroup; children = ( - F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */, + 3351C2253008164500700458 /* GoogleMapsUITests.swift */, F7151F22265D7EE50028CB91 /* Info.plist */, ); path = RunnerUITests; @@ -322,7 +322,7 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; @@ -433,7 +433,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - F7151F21265D7EE50028CB91 /* GoogleMapsUITests.m in Sources */, + F7151F21265D7EE50028CB91 /* GoogleMapsUITests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -686,6 +686,7 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; TEST_TARGET_NAME = Runner; }; name = Debug; @@ -703,6 +704,7 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; TEST_TARGET_NAME = Runner; }; name = Release; @@ -749,7 +751,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/GoogleMapsUITests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/GoogleMapsUITests.m deleted file mode 100644 index cb7fbc196b40..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/GoogleMapsUITests.m +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import CoreLocation; -@import XCTest; -@import os.log; - -static const NSTimeInterval kWaitTime = 60; - -// TODO(bparrishMines): Remove once https://github.com/flutter/flutter/issues/154641 is fixed. -static const BOOL skipFor154641 = YES; - -@interface GoogleMapsUITests : XCTestCase -@property(nonatomic, strong) XCUIApplication *app; -@end - -@implementation GoogleMapsUITests - -- (void)setUp { - self.continueAfterFailure = NO; - - self.app = [[XCUIApplication alloc] init]; - [self.app launch]; - - [self - addUIInterruptionMonitorWithDescription:@"Permission popups" - handler:^BOOL(XCUIElement *_Nonnull interruptingElement) { - if (@available(iOS 14, *)) { - XCUIElement *locationPermission = - interruptingElement.buttons[@"Allow While Using App"]; - if (![locationPermission - waitForExistenceWithTimeout:kWaitTime]) { - XCTFail(@"Failed due to not able to find " - @"locationPermission button"); - } - [locationPermission tap]; - - } else { - XCUIElement *allow = - interruptingElement.buttons[@"Allow"]; - if (![allow waitForExistenceWithTimeout:kWaitTime]) { - XCTFail(@"Failed due to not able to find Allow button"); - } - [allow tap]; - } - return YES; - }]; -} - -- (void)testUserInterface { - XCTSkipIf(skipFor154641); - - XCUIApplication *app = self.app; - XCUIElement *userInteface = app.staticTexts[@"User interface"]; - if (![userInteface waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find User interface"); - } - [userInteface tap]; - - XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; - if (![platformView waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find platform view"); - } - - // There is a known bug where the permission popups interruption won't get fired until a tap - // happened in the app. We expect a permission popup so we do a tap here. - // iOS 16 has a bug where if the app itself is directly tapped: [app tap], the first button - // (disable compass) in the app is also tapped, so instead we tap a arbitrary location in the app - // instead. - XCUICoordinate *coordinate = [app coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; - [coordinate tap]; - XCUIElement *compass = app.buttons[@"disable compass"]; - if (![compass waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find disable compass button"); - } - - [self forceTap:compass]; -} - -- (void)testMapCoordinatesPage { - XCTSkipIf(skipFor154641); - - XCUIApplication *app = self.app; - XCUIElement *mapCoordinates = app.staticTexts[@"Map coordinates"]; - if (![mapCoordinates waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'Map coordinates''"); - } - [mapCoordinates tap]; - - XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; - if (![platformView waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find platform view"); - } - - XCUIElement *titleBar = app.otherElements[@"Map coordinates"]; - if (![titleBar waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find title bar"); - } - - NSPredicate *visibleRegionPredicate = - [NSPredicate predicateWithFormat:@"label BEGINSWITH 'VisibleRegion'"]; - XCUIElement *visibleRegionText = - [app.staticTexts elementMatchingPredicate:visibleRegionPredicate]; - if (![visibleRegionText waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find Visible Region label'"); - } - - // Validate visible region does not change when scrolled under safe areas. - // https://github.com/flutter/flutter/issues/107913 - - // Example -33.79495661816674, 151.313996873796 - CLLocationCoordinate2D originalNortheast; - // Example -33.90900557679571, 151.10800322145224 - CLLocationCoordinate2D originalSouthwest; - [self validateVisibleRegion:visibleRegionText.label - northeast:&originalNortheast - southwest:&originalSouthwest]; - XCTAssertGreaterThan(originalNortheast.latitude, originalSouthwest.latitude); - XCTAssertGreaterThan(originalNortheast.longitude, originalSouthwest.longitude); - - XCTAssertLessThan(originalNortheast.latitude, 0); - XCTAssertLessThan(originalSouthwest.latitude, 0); - XCTAssertGreaterThan(originalNortheast.longitude, 0); - XCTAssertGreaterThan(originalSouthwest.longitude, 0); - - // Drag the map upward to under the title bar. - [platformView pressForDuration:0 thenDragToElement:titleBar]; - - CLLocationCoordinate2D draggedNortheast; - CLLocationCoordinate2D draggedSouthwest; - [self validateVisibleRegion:visibleRegionText.label - northeast:&draggedNortheast - southwest:&draggedSouthwest]; - XCTAssertEqual(originalNortheast.latitude, draggedNortheast.latitude); - XCTAssertEqual(originalNortheast.longitude, draggedNortheast.longitude); - XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); - XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); -} - -- (void)validateVisibleRegion:(NSString *)label - northeast:(CLLocationCoordinate2D *)northeast - southwest:(CLLocationCoordinate2D *)southwest { - // String will be "VisibleRegion:\nnortheast: LatLng(-33.79495661816674, - // 151.313996873796),\nsouthwest: LatLng(-33.90900557679571, 151.10800322145224)" - NSScanner *scan = [NSScanner scannerWithString:label]; - - // northeast - [scan scanString:@"VisibleRegion:\nnortheast: LatLng(" intoString:NULL]; - double northeastLatitude; - [scan scanDouble:&northeastLatitude]; - [scan scanString:@", " intoString:NULL]; - XCTAssertNotEqual(northeastLatitude, 0); - double northeastLongitude; - [scan scanDouble:&northeastLongitude]; - XCTAssertNotEqual(northeastLongitude, 0); - - [scan scanString:@"),\nsouthwest: LatLng(" intoString:NULL]; - double southwestLatitude; - [scan scanDouble:&southwestLatitude]; - XCTAssertNotEqual(southwestLatitude, 0); - [scan scanString:@", " intoString:NULL]; - double southwestLongitude; - [scan scanDouble:&southwestLongitude]; - XCTAssertNotEqual(southwestLongitude, 0); - *northeast = CLLocationCoordinate2DMake(northeastLatitude, northeastLongitude); - *southwest = CLLocationCoordinate2DMake(southwestLatitude, southwestLongitude); -} - -- (void)testMapClickPage { - XCTSkipIf(skipFor154641); - - XCUIApplication *app = self.app; - XCUIElement *mapClick = app.staticTexts[@"Map click"]; - if (![mapClick waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'Map click''"); - } - [mapClick tap]; - - XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; - if (![platformView waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find platform view"); - } - - [platformView tap]; - - XCUIElement *tapped = app.staticTexts[@"Tapped"]; - if (![tapped waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'tapped''"); - } - - [platformView pressForDuration:5.0]; - - XCUIElement *longPressed = app.staticTexts[@"Long pressed"]; - if (![longPressed waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'longPressed''"); - } -} - -- (void)forceTap:(XCUIElement *)button { - // iOS 16 introduced a bug where hittable is NO for buttons. We force hit the location of the - // button if that is the case. It is likely similar to - // https://github.com/flutter/flutter/issues/113377. - if (button.isHittable) { - [button tap]; - return; - } - XCUICoordinate *coordinate = [button coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; - [coordinate tap]; -} - -- (void)testMarkerDraggingCallbacks { - XCTSkipIf(skipFor154641); - - XCUIApplication *application = [[XCUIApplication alloc] init]; - [application launch]; - XCUIElement *placeMarkerButton = application.staticTexts[@"Place marker"]; - if (![placeMarkerButton waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the Place marker button."); - } - [placeMarkerButton tap]; - - XCUIElement *Add = application.buttons[@"Add"]; - if (![Add waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the Add button."); - } - [Add tap]; - - XCUIElement *marker = application.buttons[@"marker_id_1"]; - if (![marker waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the marker."); - } - [marker tap]; - - XCUIElement *toggleDraggable = application.buttons[@"toggle draggable"]; - if (![toggleDraggable waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the toggle draggable."); - } - [toggleDraggable tap]; - - // Drag marker to center - [marker pressForDuration:5 thenDragToElement:application]; - - NSPredicate *predicateDragStart = - [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragStart"]; - NSPredicate *predicateDrag = - [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDrag called"]; - NSPredicate *predicateDragEnd = - [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragEnd"]; - - XCUIElement *dragStart = [application.staticTexts matchingPredicate:predicateDragStart].element; - if (![dragStart waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the _onMarkerDragStart."); - } - XCTAssertTrue(dragStart.exists); - - XCUIElement *drag = [application.staticTexts matchingPredicate:predicateDrag].element; - if (![drag waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the _onMarkerDrag."); - } - XCTAssertTrue(drag.exists); - - XCUIElement *dragEnd = [application.staticTexts matchingPredicate:predicateDragEnd].element; - if (![dragEnd waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the _onMarkerDragEnd."); - } - XCTAssertTrue(dragEnd.exists); -} - -@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/GoogleMapsUITests.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/GoogleMapsUITests.swift new file mode 100644 index 000000000000..16c2ccd5db8b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/GoogleMapsUITests.swift @@ -0,0 +1,265 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import CoreLocation +import XCTest +import os.log + +private let kWaitTime: TimeInterval = 60 + +class GoogleMapsUITests: XCTestCase { + var app: XCUIApplication! + + override func setUp() { + super.setUp() + continueAfterFailure = false + + app = XCUIApplication() + app.launch() + + addUIInterruptionMonitor(withDescription: "Permission popups") { interruptingElement in + if #available(iOS 14, *) { + let locationPermission = interruptingElement.buttons["Allow While Using App"] + if !locationPermission.waitForExistence(timeout: kWaitTime) { + XCTFail("Failed due to not able to find locationPermission button") + } + locationPermission.tap() + } else { + let allow = interruptingElement.buttons["Allow"] + if !allow.waitForExistence(timeout: kWaitTime) { + XCTFail("Failed due to not able to find Allow button") + } + allow.tap() + } + return true + } + } + + func testUserInterface() throws { + let userInterface = app.buttons["User interface"] + if !userInterface.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find User interface") + } + userInterface.tap() + + let platformView = app.otherElements["platform_view[0]"] + if !platformView.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find platform view") + } + + // There is a known bug where the permission popups interruption won't get fired until a tap + // happened in the app. We expect a permission popup so we do a tap here. + // iOS 16 has a bug where if the app itself is directly tapped: [app tap], the first button + // (disable compass) in the app is also tapped, so instead we tap a arbitrary location in the app + // instead. + let coordinate = app.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)) + coordinate.tap() + let compass = app.buttons["disable compass"] + if !compass.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find disable compass button") + } + + forceTap(compass) + } + + func testMapCoordinatesPage() throws { + let mapCoordinates = app.buttons["Map coordinates"] + if !mapCoordinates.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'Map coordinates'") + } + mapCoordinates.tap() + + let platformView = app.otherElements["platform_view[0]"] + if !platformView.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find platform view") + } + + let titleBar = app.staticTexts["Map coordinates"] + if !titleBar.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find title bar") + } + + let visibleRegionPredicate = NSPredicate(format: "label BEGINSWITH 'VisibleRegion'") + let visibleRegionText = app.staticTexts.element(matching: visibleRegionPredicate) + if !visibleRegionText.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find Visible Region label") + } + + // Validate visible region does not change when scrolled under safe areas. + // https://github.com/flutter/flutter/issues/107913 + + // Example -33.79495661816674, 151.313996873796 + let (originalNortheast, originalSouthwest) = try XCTUnwrap( + validateVisibleRegion(visibleRegionText.label) + ) + XCTAssertGreaterThan(originalNortheast.latitude, originalSouthwest.latitude) + XCTAssertGreaterThan(originalNortheast.longitude, originalSouthwest.longitude) + + XCTAssertLessThan(originalNortheast.latitude, 0) + XCTAssertLessThan(originalSouthwest.latitude, 0) + XCTAssertGreaterThan(originalNortheast.longitude, 0) + XCTAssertGreaterThan(originalSouthwest.longitude, 0) + + // Drag the map upward to under the title bar. + platformView.press(forDuration: 0, thenDragTo: titleBar) + + let (draggedNortheast, draggedSouthwest) = try XCTUnwrap( + validateVisibleRegion(visibleRegionText.label) + ) + XCTAssertEqual(originalNortheast.latitude, draggedNortheast.latitude) + XCTAssertEqual(originalNortheast.longitude, draggedNortheast.longitude) + XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude) + XCTAssertEqual(originalSouthwest.longitude, draggedSouthwest.longitude) + } + + func validateVisibleRegion( + _ label: String + ) -> (northeast: CLLocationCoordinate2D, southwest: CLLocationCoordinate2D)? { + // String will be "VisibleRegion:\nnortheast: LatLng(-33.79495661816674, + // 151.313996873796),\nsouthwest: LatLng(-33.90900557679571, 151.10800322145224)" + let scan = Scanner(string: label) + + // northeast + _ = scan.scanString("VisibleRegion:\nnortheast: LatLng(") + guard let northeastLatitude = scan.scanDouble() else { + XCTFail("Failed to scan northeastLatitude") + return nil + } + _ = scan.scanString(", ") + XCTAssertNotEqual(northeastLatitude, 0) + guard let northeastLongitude = scan.scanDouble() else { + XCTFail("Failed to scan northeastLongitude") + return nil + } + XCTAssertNotEqual(northeastLongitude, 0) + + _ = scan.scanString("),\nsouthwest: LatLng(") + guard let southwestLatitude = scan.scanDouble() else { + XCTFail("Failed to scan southwestLatitude") + return nil + } + XCTAssertNotEqual(southwestLatitude, 0) + _ = scan.scanString(", ") + guard let southwestLongitude = scan.scanDouble() else { + XCTFail("Failed to scan southwestLongitude") + return nil + } + XCTAssertNotEqual(southwestLongitude, 0) + + return ( + CLLocationCoordinate2D(latitude: northeastLatitude, longitude: northeastLongitude), + CLLocationCoordinate2D(latitude: southwestLatitude, longitude: southwestLongitude) + ) + } + + func testMapClickPage() throws { + let mapClick = app.buttons["Map click"] + if !mapClick.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'Map click'") + } + mapClick.tap() + + let platformView = app.otherElements["platform_view[0]"] + if !platformView.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find platform view") + } + + platformView.tap() + + let tapped = app.staticTexts["Tapped"] + if !tapped.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'tapped'") + } + + platformView.press(forDuration: 5.0) + + let longPressed = app.staticTexts["Long pressed"] + if !longPressed.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'longPressed'") + } + } + + func forceTap(_ button: XCUIElement) { + // iOS 16 introduced a bug where hittable is NO for buttons. We force hit the location of the + // button if that is the case. It is likely similar to + // https://github.com/flutter/flutter/issues/113377. + if button.isHittable { + button.tap() + return + } + let coordinate = button.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)) + coordinate.tap() + } + + func testMarkerDraggingCallbacks() throws { + let application = XCUIApplication() + application.launch() + let placeMarkerButton = application.buttons["Place marker"] + if !placeMarkerButton.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the Place marker button.") + } + placeMarkerButton.tap() + + let add = application.buttons["Add"] + if !add.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the Add button.") + } + add.tap() + + let marker = application.buttons["marker_id_1"] + if !marker.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the marker.") + } + marker.tap() + + let toggleDraggable = application.buttons["toggle draggable"] + if !toggleDraggable.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the toggle draggable.") + } + toggleDraggable.tap() + + // Drag marker to center + marker.press(forDuration: 5, thenDragTo: application) + + let predicateDragStart = NSPredicate(format: "label CONTAINS[c] %@", "_onMarkerDragStart") + let predicateDrag = NSPredicate(format: "label CONTAINS[c] %@", "_onMarkerDrag called") + let predicateDragEnd = NSPredicate(format: "label CONTAINS[c] %@", "_onMarkerDragEnd") + + let dragStart = application.staticTexts.matching(predicateDragStart).element + if !dragStart.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the _onMarkerDragStart.") + } + XCTAssertTrue(dragStart.exists) + + let drag = application.staticTexts.matching(predicateDrag).element + if !drag.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the _onMarkerDrag.") + } + XCTAssertTrue(drag.exists) + + let dragEnd = application.staticTexts.matching(predicateDragEnd).element + if !dragEnd.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the _onMarkerDragEnd.") + } + XCTAssertTrue(dragEnd.exists) + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerUITests/GoogleMapsUITests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerUITests/GoogleMapsUITests.m deleted file mode 100644 index cb7fbc196b40..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerUITests/GoogleMapsUITests.m +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import CoreLocation; -@import XCTest; -@import os.log; - -static const NSTimeInterval kWaitTime = 60; - -// TODO(bparrishMines): Remove once https://github.com/flutter/flutter/issues/154641 is fixed. -static const BOOL skipFor154641 = YES; - -@interface GoogleMapsUITests : XCTestCase -@property(nonatomic, strong) XCUIApplication *app; -@end - -@implementation GoogleMapsUITests - -- (void)setUp { - self.continueAfterFailure = NO; - - self.app = [[XCUIApplication alloc] init]; - [self.app launch]; - - [self - addUIInterruptionMonitorWithDescription:@"Permission popups" - handler:^BOOL(XCUIElement *_Nonnull interruptingElement) { - if (@available(iOS 14, *)) { - XCUIElement *locationPermission = - interruptingElement.buttons[@"Allow While Using App"]; - if (![locationPermission - waitForExistenceWithTimeout:kWaitTime]) { - XCTFail(@"Failed due to not able to find " - @"locationPermission button"); - } - [locationPermission tap]; - - } else { - XCUIElement *allow = - interruptingElement.buttons[@"Allow"]; - if (![allow waitForExistenceWithTimeout:kWaitTime]) { - XCTFail(@"Failed due to not able to find Allow button"); - } - [allow tap]; - } - return YES; - }]; -} - -- (void)testUserInterface { - XCTSkipIf(skipFor154641); - - XCUIApplication *app = self.app; - XCUIElement *userInteface = app.staticTexts[@"User interface"]; - if (![userInteface waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find User interface"); - } - [userInteface tap]; - - XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; - if (![platformView waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find platform view"); - } - - // There is a known bug where the permission popups interruption won't get fired until a tap - // happened in the app. We expect a permission popup so we do a tap here. - // iOS 16 has a bug where if the app itself is directly tapped: [app tap], the first button - // (disable compass) in the app is also tapped, so instead we tap a arbitrary location in the app - // instead. - XCUICoordinate *coordinate = [app coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; - [coordinate tap]; - XCUIElement *compass = app.buttons[@"disable compass"]; - if (![compass waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find disable compass button"); - } - - [self forceTap:compass]; -} - -- (void)testMapCoordinatesPage { - XCTSkipIf(skipFor154641); - - XCUIApplication *app = self.app; - XCUIElement *mapCoordinates = app.staticTexts[@"Map coordinates"]; - if (![mapCoordinates waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'Map coordinates''"); - } - [mapCoordinates tap]; - - XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; - if (![platformView waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find platform view"); - } - - XCUIElement *titleBar = app.otherElements[@"Map coordinates"]; - if (![titleBar waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find title bar"); - } - - NSPredicate *visibleRegionPredicate = - [NSPredicate predicateWithFormat:@"label BEGINSWITH 'VisibleRegion'"]; - XCUIElement *visibleRegionText = - [app.staticTexts elementMatchingPredicate:visibleRegionPredicate]; - if (![visibleRegionText waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find Visible Region label'"); - } - - // Validate visible region does not change when scrolled under safe areas. - // https://github.com/flutter/flutter/issues/107913 - - // Example -33.79495661816674, 151.313996873796 - CLLocationCoordinate2D originalNortheast; - // Example -33.90900557679571, 151.10800322145224 - CLLocationCoordinate2D originalSouthwest; - [self validateVisibleRegion:visibleRegionText.label - northeast:&originalNortheast - southwest:&originalSouthwest]; - XCTAssertGreaterThan(originalNortheast.latitude, originalSouthwest.latitude); - XCTAssertGreaterThan(originalNortheast.longitude, originalSouthwest.longitude); - - XCTAssertLessThan(originalNortheast.latitude, 0); - XCTAssertLessThan(originalSouthwest.latitude, 0); - XCTAssertGreaterThan(originalNortheast.longitude, 0); - XCTAssertGreaterThan(originalSouthwest.longitude, 0); - - // Drag the map upward to under the title bar. - [platformView pressForDuration:0 thenDragToElement:titleBar]; - - CLLocationCoordinate2D draggedNortheast; - CLLocationCoordinate2D draggedSouthwest; - [self validateVisibleRegion:visibleRegionText.label - northeast:&draggedNortheast - southwest:&draggedSouthwest]; - XCTAssertEqual(originalNortheast.latitude, draggedNortheast.latitude); - XCTAssertEqual(originalNortheast.longitude, draggedNortheast.longitude); - XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); - XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); -} - -- (void)validateVisibleRegion:(NSString *)label - northeast:(CLLocationCoordinate2D *)northeast - southwest:(CLLocationCoordinate2D *)southwest { - // String will be "VisibleRegion:\nnortheast: LatLng(-33.79495661816674, - // 151.313996873796),\nsouthwest: LatLng(-33.90900557679571, 151.10800322145224)" - NSScanner *scan = [NSScanner scannerWithString:label]; - - // northeast - [scan scanString:@"VisibleRegion:\nnortheast: LatLng(" intoString:NULL]; - double northeastLatitude; - [scan scanDouble:&northeastLatitude]; - [scan scanString:@", " intoString:NULL]; - XCTAssertNotEqual(northeastLatitude, 0); - double northeastLongitude; - [scan scanDouble:&northeastLongitude]; - XCTAssertNotEqual(northeastLongitude, 0); - - [scan scanString:@"),\nsouthwest: LatLng(" intoString:NULL]; - double southwestLatitude; - [scan scanDouble:&southwestLatitude]; - XCTAssertNotEqual(southwestLatitude, 0); - [scan scanString:@", " intoString:NULL]; - double southwestLongitude; - [scan scanDouble:&southwestLongitude]; - XCTAssertNotEqual(southwestLongitude, 0); - *northeast = CLLocationCoordinate2DMake(northeastLatitude, northeastLongitude); - *southwest = CLLocationCoordinate2DMake(southwestLatitude, southwestLongitude); -} - -- (void)testMapClickPage { - XCTSkipIf(skipFor154641); - - XCUIApplication *app = self.app; - XCUIElement *mapClick = app.staticTexts[@"Map click"]; - if (![mapClick waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'Map click''"); - } - [mapClick tap]; - - XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; - if (![platformView waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find platform view"); - } - - [platformView tap]; - - XCUIElement *tapped = app.staticTexts[@"Tapped"]; - if (![tapped waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'tapped''"); - } - - [platformView pressForDuration:5.0]; - - XCUIElement *longPressed = app.staticTexts[@"Long pressed"]; - if (![longPressed waitForExistenceWithTimeout:kWaitTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); - XCTFail(@"Failed due to not able to find 'longPressed''"); - } -} - -- (void)forceTap:(XCUIElement *)button { - // iOS 16 introduced a bug where hittable is NO for buttons. We force hit the location of the - // button if that is the case. It is likely similar to - // https://github.com/flutter/flutter/issues/113377. - if (button.isHittable) { - [button tap]; - return; - } - XCUICoordinate *coordinate = [button coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; - [coordinate tap]; -} - -- (void)testMarkerDraggingCallbacks { - XCTSkipIf(skipFor154641); - - XCUIApplication *application = [[XCUIApplication alloc] init]; - [application launch]; - XCUIElement *placeMarkerButton = application.staticTexts[@"Place marker"]; - if (![placeMarkerButton waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the Place marker button."); - } - [placeMarkerButton tap]; - - XCUIElement *Add = application.buttons[@"Add"]; - if (![Add waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the Add button."); - } - [Add tap]; - - XCUIElement *marker = application.buttons[@"marker_id_1"]; - if (![marker waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the marker."); - } - [marker tap]; - - XCUIElement *toggleDraggable = application.buttons[@"toggle draggable"]; - if (![toggleDraggable waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the toggle draggable."); - } - [toggleDraggable tap]; - - // Drag marker to center - [marker pressForDuration:5 thenDragToElement:application]; - - NSPredicate *predicateDragStart = - [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragStart"]; - NSPredicate *predicateDrag = - [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDrag called"]; - NSPredicate *predicateDragEnd = - [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragEnd"]; - - XCUIElement *dragStart = [application.staticTexts matchingPredicate:predicateDragStart].element; - if (![dragStart waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the _onMarkerDragStart."); - } - XCTAssertTrue(dragStart.exists); - - XCUIElement *drag = [application.staticTexts matchingPredicate:predicateDrag].element; - if (![drag waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the _onMarkerDrag."); - } - XCTAssertTrue(drag.exists); - - XCUIElement *dragEnd = [application.staticTexts matchingPredicate:predicateDragEnd].element; - if (![dragEnd waitForExistenceWithTimeout:kWaitTime]) { - NSLog(@"application.debugDescription: %@", application.debugDescription); - XCTFail(@"Failed to find the _onMarkerDragEnd."); - } - XCTAssertTrue(dragEnd.exists); -} - -@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerUITests/GoogleMapsUITests.swift b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerUITests/GoogleMapsUITests.swift new file mode 100644 index 000000000000..16c2ccd5db8b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerUITests/GoogleMapsUITests.swift @@ -0,0 +1,265 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import CoreLocation +import XCTest +import os.log + +private let kWaitTime: TimeInterval = 60 + +class GoogleMapsUITests: XCTestCase { + var app: XCUIApplication! + + override func setUp() { + super.setUp() + continueAfterFailure = false + + app = XCUIApplication() + app.launch() + + addUIInterruptionMonitor(withDescription: "Permission popups") { interruptingElement in + if #available(iOS 14, *) { + let locationPermission = interruptingElement.buttons["Allow While Using App"] + if !locationPermission.waitForExistence(timeout: kWaitTime) { + XCTFail("Failed due to not able to find locationPermission button") + } + locationPermission.tap() + } else { + let allow = interruptingElement.buttons["Allow"] + if !allow.waitForExistence(timeout: kWaitTime) { + XCTFail("Failed due to not able to find Allow button") + } + allow.tap() + } + return true + } + } + + func testUserInterface() throws { + let userInterface = app.buttons["User interface"] + if !userInterface.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find User interface") + } + userInterface.tap() + + let platformView = app.otherElements["platform_view[0]"] + if !platformView.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find platform view") + } + + // There is a known bug where the permission popups interruption won't get fired until a tap + // happened in the app. We expect a permission popup so we do a tap here. + // iOS 16 has a bug where if the app itself is directly tapped: [app tap], the first button + // (disable compass) in the app is also tapped, so instead we tap a arbitrary location in the app + // instead. + let coordinate = app.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)) + coordinate.tap() + let compass = app.buttons["disable compass"] + if !compass.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find disable compass button") + } + + forceTap(compass) + } + + func testMapCoordinatesPage() throws { + let mapCoordinates = app.buttons["Map coordinates"] + if !mapCoordinates.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'Map coordinates'") + } + mapCoordinates.tap() + + let platformView = app.otherElements["platform_view[0]"] + if !platformView.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find platform view") + } + + let titleBar = app.staticTexts["Map coordinates"] + if !titleBar.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find title bar") + } + + let visibleRegionPredicate = NSPredicate(format: "label BEGINSWITH 'VisibleRegion'") + let visibleRegionText = app.staticTexts.element(matching: visibleRegionPredicate) + if !visibleRegionText.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find Visible Region label") + } + + // Validate visible region does not change when scrolled under safe areas. + // https://github.com/flutter/flutter/issues/107913 + + // Example -33.79495661816674, 151.313996873796 + let (originalNortheast, originalSouthwest) = try XCTUnwrap( + validateVisibleRegion(visibleRegionText.label) + ) + XCTAssertGreaterThan(originalNortheast.latitude, originalSouthwest.latitude) + XCTAssertGreaterThan(originalNortheast.longitude, originalSouthwest.longitude) + + XCTAssertLessThan(originalNortheast.latitude, 0) + XCTAssertLessThan(originalSouthwest.latitude, 0) + XCTAssertGreaterThan(originalNortheast.longitude, 0) + XCTAssertGreaterThan(originalSouthwest.longitude, 0) + + // Drag the map upward to under the title bar. + platformView.press(forDuration: 0, thenDragTo: titleBar) + + let (draggedNortheast, draggedSouthwest) = try XCTUnwrap( + validateVisibleRegion(visibleRegionText.label) + ) + XCTAssertEqual(originalNortheast.latitude, draggedNortheast.latitude) + XCTAssertEqual(originalNortheast.longitude, draggedNortheast.longitude) + XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude) + XCTAssertEqual(originalSouthwest.longitude, draggedSouthwest.longitude) + } + + func validateVisibleRegion( + _ label: String + ) -> (northeast: CLLocationCoordinate2D, southwest: CLLocationCoordinate2D)? { + // String will be "VisibleRegion:\nnortheast: LatLng(-33.79495661816674, + // 151.313996873796),\nsouthwest: LatLng(-33.90900557679571, 151.10800322145224)" + let scan = Scanner(string: label) + + // northeast + _ = scan.scanString("VisibleRegion:\nnortheast: LatLng(") + guard let northeastLatitude = scan.scanDouble() else { + XCTFail("Failed to scan northeastLatitude") + return nil + } + _ = scan.scanString(", ") + XCTAssertNotEqual(northeastLatitude, 0) + guard let northeastLongitude = scan.scanDouble() else { + XCTFail("Failed to scan northeastLongitude") + return nil + } + XCTAssertNotEqual(northeastLongitude, 0) + + _ = scan.scanString("),\nsouthwest: LatLng(") + guard let southwestLatitude = scan.scanDouble() else { + XCTFail("Failed to scan southwestLatitude") + return nil + } + XCTAssertNotEqual(southwestLatitude, 0) + _ = scan.scanString(", ") + guard let southwestLongitude = scan.scanDouble() else { + XCTFail("Failed to scan southwestLongitude") + return nil + } + XCTAssertNotEqual(southwestLongitude, 0) + + return ( + CLLocationCoordinate2D(latitude: northeastLatitude, longitude: northeastLongitude), + CLLocationCoordinate2D(latitude: southwestLatitude, longitude: southwestLongitude) + ) + } + + func testMapClickPage() throws { + let mapClick = app.buttons["Map click"] + if !mapClick.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'Map click'") + } + mapClick.tap() + + let platformView = app.otherElements["platform_view[0]"] + if !platformView.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find platform view") + } + + platformView.tap() + + let tapped = app.staticTexts["Tapped"] + if !tapped.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'tapped'") + } + + platformView.press(forDuration: 5.0) + + let longPressed = app.staticTexts["Long pressed"] + if !longPressed.waitForExistence(timeout: kWaitTime) { + os_log("%@", log: .default, type: .error, app.debugDescription as NSString) + XCTFail("Failed due to not able to find 'longPressed'") + } + } + + func forceTap(_ button: XCUIElement) { + // iOS 16 introduced a bug where hittable is NO for buttons. We force hit the location of the + // button if that is the case. It is likely similar to + // https://github.com/flutter/flutter/issues/113377. + if button.isHittable { + button.tap() + return + } + let coordinate = button.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)) + coordinate.tap() + } + + func testMarkerDraggingCallbacks() throws { + let application = XCUIApplication() + application.launch() + let placeMarkerButton = application.buttons["Place marker"] + if !placeMarkerButton.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the Place marker button.") + } + placeMarkerButton.tap() + + let add = application.buttons["Add"] + if !add.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the Add button.") + } + add.tap() + + let marker = application.buttons["marker_id_1"] + if !marker.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the marker.") + } + marker.tap() + + let toggleDraggable = application.buttons["toggle draggable"] + if !toggleDraggable.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the toggle draggable.") + } + toggleDraggable.tap() + + // Drag marker to center + marker.press(forDuration: 5, thenDragTo: application) + + let predicateDragStart = NSPredicate(format: "label CONTAINS[c] %@", "_onMarkerDragStart") + let predicateDrag = NSPredicate(format: "label CONTAINS[c] %@", "_onMarkerDrag called") + let predicateDragEnd = NSPredicate(format: "label CONTAINS[c] %@", "_onMarkerDragEnd") + + let dragStart = application.staticTexts.matching(predicateDragStart).element + if !dragStart.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the _onMarkerDragStart.") + } + XCTAssertTrue(dragStart.exists) + + let drag = application.staticTexts.matching(predicateDrag).element + if !drag.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the _onMarkerDrag.") + } + XCTAssertTrue(drag.exists) + + let dragEnd = application.staticTexts.matching(predicateDragEnd).element + if !dragEnd.waitForExistence(timeout: kWaitTime) { + NSLog("application.debugDescription: %@", application.debugDescription as NSString) + XCTFail("Failed to find the _onMarkerDragEnd.") + } + XCTAssertTrue(dragEnd.exists) + } +}