diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AppSyncRealTimeClientFactory.swift b/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AppSyncRealTimeClientFactory.swift index 9f30e88c8f..7b8d1b21c9 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AppSyncRealTimeClientFactory.swift +++ b/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AppSyncRealTimeClientFactory.swift @@ -136,7 +136,7 @@ extension AppSyncRealTimeClientFactory { return url } - guard host.hasSuffix("amazonaws.com") else { + guard host.hasSuffix("amazonaws.com") || host.hasSuffix("amazonaws.com.cn") else { return url.appendingPathComponent("realtime") } @@ -163,7 +163,7 @@ extension AppSyncRealTimeClientFactory { return url } - guard host.hasSuffix("amazonaws.com") else { + guard host.hasSuffix("amazonaws.com") || host.hasSuffix("amazonaws.com.cn") else { if url.lastPathComponent == "realtime" { return url.deletingLastPathComponent() } diff --git a/AmplifyPlugins/API/Tests/AWSAPIPluginTests/SubscriptionFactory/AppSyncRealTimeClientFactoryTests.swift b/AmplifyPlugins/API/Tests/AWSAPIPluginTests/SubscriptionFactory/AppSyncRealTimeClientFactoryTests.swift index 15ca8c7858..6d3ebbd8fd 100644 --- a/AmplifyPlugins/API/Tests/AWSAPIPluginTests/SubscriptionFactory/AppSyncRealTimeClientFactoryTests.swift +++ b/AmplifyPlugins/API/Tests/AWSAPIPluginTests/SubscriptionFactory/AppSyncRealTimeClientFactoryTests.swift @@ -17,6 +17,12 @@ class AppSyncRealTimeClientFactoryTests: XCTestCase { AppSyncRealTimeClientFactory.appSyncRealTimeEndpoint(appSyncEndpoint), URL(string: "wss://abc.appsync-realtime-api.amazonaws.com/graphql") ) + + let appSyncEndpointCN = URL(string: "https://abc.appsync-api.amazonaws.com.cn/graphql")! + XCTAssertEqual( + AppSyncRealTimeClientFactory.appSyncRealTimeEndpoint(appSyncEndpointCN), + URL(string: "wss://abc.appsync-realtime-api.amazonaws.com.cn/graphql") + ) } func testAppSyncRealTimeEndpoint_withAWSAppSyncRealTimeDomain_returnTheSameDomain() { @@ -25,6 +31,12 @@ class AppSyncRealTimeClientFactoryTests: XCTestCase { AppSyncRealTimeClientFactory.appSyncRealTimeEndpoint(appSyncEndpoint), URL(string: "wss://abc.appsync-realtime-api.amazonaws.com/graphql") ) + + let appSyncEndpointCN = URL(string: "wss://abc.appsync-realtime-api.amazonaws.com.cn/graphql")! + XCTAssertEqual( + AppSyncRealTimeClientFactory.appSyncRealTimeEndpoint(appSyncEndpointCN), + URL(string: "wss://abc.appsync-realtime-api.amazonaws.com.cn/graphql") + ) } func testAppSyncRealTimeEndpoint_withCustomDomain_returnCorrectRealtimePath() { @@ -33,6 +45,12 @@ class AppSyncRealTimeClientFactoryTests: XCTestCase { AppSyncRealTimeClientFactory.appSyncRealTimeEndpoint(appSyncEndpoint), URL(string: "https://test.example.com/graphql/realtime") ) + + let appSyncEndpointCN = URL(string: "https://test.example.com.cn/graphql")! + XCTAssertEqual( + AppSyncRealTimeClientFactory.appSyncRealTimeEndpoint(appSyncEndpointCN), + URL(string: "https://test.example.com.cn/graphql/realtime") + ) } func testAppSyncApiEndpoint_withAWSAppSyncRealTimeDomain_returnCorrectApiDomain() { @@ -41,6 +59,12 @@ class AppSyncRealTimeClientFactoryTests: XCTestCase { AppSyncRealTimeClientFactory.appSyncApiEndpoint(appSyncEndpoint), URL(string: "https://abc.appsync-api.amazonaws.com/graphql") ) + + let appSyncEndpointCN = URL(string: "wss://abc.appsync-realtime-api.amazonaws.com.cn/graphql")! + XCTAssertEqual( + AppSyncRealTimeClientFactory.appSyncApiEndpoint(appSyncEndpointCN), + URL(string: "https://abc.appsync-api.amazonaws.com.cn/graphql") + ) } func testAppSyncApiEndpoint_withAWSAppSyncApiDomain_returnTheSameDomain() { @@ -49,6 +73,12 @@ class AppSyncRealTimeClientFactoryTests: XCTestCase { AppSyncRealTimeClientFactory.appSyncApiEndpoint(appSyncEndpoint), URL(string: "https://abc.appsync-api.amazonaws.com/graphql") ) + + let appSyncEndpointCN = URL(string: "https://abc.appsync-api.amazonaws.com.cn/graphql")! + XCTAssertEqual( + AppSyncRealTimeClientFactory.appSyncApiEndpoint(appSyncEndpointCN), + URL(string: "https://abc.appsync-api.amazonaws.com.cn/graphql") + ) } func testAppSyncApiEndpoint_withCustomDomain_returnCorrectRealtimePath() { @@ -57,5 +87,11 @@ class AppSyncRealTimeClientFactoryTests: XCTestCase { AppSyncRealTimeClientFactory.appSyncApiEndpoint(appSyncEndpoint), URL(string: "https://test.example.com/graphql") ) + + let appSyncEndpointCN = URL(string: "https://test.example.com.cn/graphql")! + XCTAssertEqual( + AppSyncRealTimeClientFactory.appSyncApiEndpoint(appSyncEndpointCN), + URL(string: "https://test.example.com.cn/graphql") + ) } } diff --git a/AmplifyPlugins/Auth/Tests/AuthWebAuthnApp/AuthWebAuthnAppUITests/AuthWebAuthnAppUITests.swift b/AmplifyPlugins/Auth/Tests/AuthWebAuthnApp/AuthWebAuthnAppUITests/AuthWebAuthnAppUITests.swift index e6283ebdc6..6bf7be539a 100644 --- a/AmplifyPlugins/Auth/Tests/AuthWebAuthnApp/AuthWebAuthnAppUITests/AuthWebAuthnAppUITests.swift +++ b/AmplifyPlugins/Auth/Tests/AuthWebAuthnApp/AuthWebAuthnAppUITests/AuthWebAuthnAppUITests.swift @@ -19,9 +19,6 @@ final class AuthWebAuthnAppUITests: XCTestCase { private var deleteButton: XCUIElement! private var deleteUserButton: XCUIElement! private var springboard: XCUIApplication! - private var continueButton: XCUIElement! { - springboard.otherElements["ASAuthorizationControllerContinueButton"] - } private lazy var deviceIdentifier: String = { let paths = Bundle.main.bundleURL.pathComponents @@ -81,35 +78,36 @@ final class AuthWebAuthnAppUITests: XCTestCase { } guard associateAttempt else { - XCTFail("Failed to trigger the Associate WebAuthn Credential workflow") + XCTFail("Failed to trigger the Associate WebAuthn Credential workflow: \(lastResult)") return } // Wait for the "Continue" button to appear in the FaceID popover and tap it - guard continueButton.waitForExistence(timeout: timeout) else { - XCTFail("Failed to find 'Continue' button") + let associateContinueButton = springboard.otherElements["ASAuthorizationControllerContinueButton"] + guard associateContinueButton.waitForExistence(timeout: timeout) else { + XCTFail("Failed to find the 'Continue' button to Associate new WebAuthn credential") return } - continueButton.tap() + associateContinueButton.tap() // Trigger a matching face try await matchBiometrics() guard waitForResult("WebAuthn credential was associated") else { - XCTFail("Failed to associate credential") + XCTFail("Failed to associate credential: \(lastResult)") return } // 2. List existing credentials listButton.tap() guard waitForResult("WebAuthn Credentials: 1") else { - XCTFail("Failed to list credentials") + XCTFail("Failed to list credentials: \(lastResult)") return } // 3. Sign Out signOutButton.tap() guard waitForResult("User is signed out"), signInButton.exists else { - XCTFail("Failed to sign out user") + XCTFail("Failed to sign out user: \(lastResult)") return } @@ -120,13 +118,14 @@ final class AuthWebAuthnAppUITests: XCTestCase { } guard signInAttempt else { - XCTFail("Failed to trigger the Assert WebAuthn Credential workflow") + XCTFail("Failed to trigger the Assert WebAuthn Credential workflow: \(lastResult)") return } // Wait for the "Continue" button to appear in the FaceID popover - guard continueButton.waitForExistence(timeout: timeout) else { - XCTFail("Failed to find 'Continue' button") + let signInContinueButton = springboard.otherElements["ASAuthorizationControllerContinueButton"] + guard signInContinueButton.waitForExistence(timeout: timeout) else { + XCTFail("Failed to find the 'Continue' button to Sign In with WebAuthn") return } @@ -137,27 +136,27 @@ final class AuthWebAuthnAppUITests: XCTestCase { } // Tap the "Continue" button - continueButton.tap() + signInContinueButton.tap() // Trigger a matching face try await matchBiometrics() guard waitForResult("User is signed in") else { - XCTFail("Failed to Sign In with WebAuthn") + XCTFail("Failed to Sign In with WebAuthn: \(lastResult)") return } // 5. Delete credential deleteButton.tap() guard waitForResult("WebAuthn credential was deleted") else { - XCTFail("Failed to delete credential") + XCTFail("Failed to delete credential: \(lastResult)") return } // 6. Verify deletion listButton.tap() guard waitForResult("WebAuthn Credentials: 0") else { - XCTFail("Failed to list credentials") + XCTFail("Failed to list credentials: \(lastResult)") return } } @@ -194,7 +193,7 @@ final class AuthWebAuthnAppUITests: XCTestCase { return } - username = usernameElement.label + username = usernameElement.label.lowercased() // Once the Username label exists, all these button are expected to visible as well, // so we don't wait for them and instead just check for their existence @@ -240,7 +239,7 @@ final class AuthWebAuthnAppUITests: XCTestCase { private func signUpAndSignInUser() { signUpButton.tap() guard waitForResult("User is signed in"), signOutButton.exists else { - XCTFail("Failed to Sign Up and Sign In") + XCTFail("Failed to Sign Up and Sign In: \(lastResult)") return } } @@ -253,7 +252,7 @@ final class AuthWebAuthnAppUITests: XCTestCase { } deleteUserButton.tap() guard waitForResult("User was deleted"), signUpButton.exists else { - XCTFail("Failed to delete the user") + XCTFail("Failed to delete the user: \(lastResult)") return } } @@ -275,4 +274,8 @@ final class AuthWebAuthnAppUITests: XCTestCase { } return result } + + private var lastResult: String { + app.staticTexts["LastResult"].label + } }