-
Notifications
You must be signed in to change notification settings - Fork 3.6k
[google_sign_in] Convert iOS tests to Swift #10787
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[google_sign_in] Convert iOS tests to Swift #10787
Conversation
|
@jmagman Do you want to review the Swift Testing aspect here since you've been looking at it? (This PR was prompted by wanting to get some hands-on experience with Swift Testing, and I'd been wanting to do the Swift conversion here already, so it seemed like a good opportunity to do both.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request is a great step forward, successfully converting the iOS unit tests from Objective-C to Swift and adopting the new Swift Testing framework. The code is well-structured, and the refactoring to reduce global state by introducing helper functions significantly improves test isolation and readability. I have a few minor suggestions to further enhance the clarity and robustness of the new Swift tests.
packages/google_sign_in/google_sign_in_ios/darwin/Tests/GoogleSignInTests.swift
Outdated
Show resolved
Hide resolved
packages/google_sign_in/google_sign_in_ios/darwin/Tests/GoogleSignInTests.swift
Outdated
Show resolved
Hide resolved
packages/google_sign_in/google_sign_in_ios/darwin/Tests/GoogleSignInTests.swift
Outdated
Show resolved
Hide resolved
| #expect(result?.error == nil) | ||
| #expect(result?.success != nil) | ||
| #expect(result?.success?.user.displayName == fakeUserProfile.name) | ||
| #expect(result?.success?.user.email == fakeUserProfile.email) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see warnings in Xcode:
Implicit capture of 'fakeUserProfile' requires that 'TestProfileData' conforms to 'Sendable'
Class 'TestProfileData' does not conform to the 'Sendable' protocol
Do the test fake helper classes inheriting from Objective-C classes need @unchecked Sendable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I adjusted the test to only pass primitive types into the callback, rather than the test types.
| @Test func refreshTokensNoAuthKeychainError() async { | ||
| let plugin = createTestPlugin() | ||
| let fakeUser = addSignedInUser(to: plugin) | ||
|
|
||
| let sdkError = NSError( | ||
| domain: kGIDSignInErrorDomain, code: GIDSignInError.hasNoAuthInKeychain.rawValue, | ||
| userInfo: nil) | ||
| fakeUser.error = sdkError | ||
|
|
||
| await confirmation("completion called") { confirmed in | ||
| plugin.refreshedAuthorizationTokens(forUser: fakeUser.userID!) { result, error in | ||
| #expect(error == nil) | ||
| #expect(result?.success == nil) | ||
| #expect(result?.error?.type == .noAuthInKeychain) | ||
| confirmed() | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Test func refreshTokensCancelledError() async { | ||
| let plugin = createTestPlugin() | ||
| let fakeUser = addSignedInUser(to: plugin) | ||
|
|
||
| let sdkError = NSError( | ||
| domain: kGIDSignInErrorDomain, code: GIDSignInError.canceled.rawValue, userInfo: nil) | ||
| fakeUser.error = sdkError | ||
|
|
||
| await confirmation("completion called") { confirmed in | ||
| plugin.refreshedAuthorizationTokens(forUser: fakeUser.userID!) { result, error in | ||
| #expect(error == nil) | ||
| #expect(result?.success == nil) | ||
| #expect(result?.error?.type == .canceled) | ||
| confirmed() | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can get pretty cute with test parameterization (if you want to in this review, or the mechanical change is fine too).
For example, you can collapse these two tests into one, with parameters:
| @Test func refreshTokensNoAuthKeychainError() async { | |
| let plugin = createTestPlugin() | |
| let fakeUser = addSignedInUser(to: plugin) | |
| let sdkError = NSError( | |
| domain: kGIDSignInErrorDomain, code: GIDSignInError.hasNoAuthInKeychain.rawValue, | |
| userInfo: nil) | |
| fakeUser.error = sdkError | |
| await confirmation("completion called") { confirmed in | |
| plugin.refreshedAuthorizationTokens(forUser: fakeUser.userID!) { result, error in | |
| #expect(error == nil) | |
| #expect(result?.success == nil) | |
| #expect(result?.error?.type == .noAuthInKeychain) | |
| confirmed() | |
| } | |
| } | |
| } | |
| @Test func refreshTokensCancelledError() async { | |
| let plugin = createTestPlugin() | |
| let fakeUser = addSignedInUser(to: plugin) | |
| let sdkError = NSError( | |
| domain: kGIDSignInErrorDomain, code: GIDSignInError.canceled.rawValue, userInfo: nil) | |
| fakeUser.error = sdkError | |
| await confirmation("completion called") { confirmed in | |
| plugin.refreshedAuthorizationTokens(forUser: fakeUser.userID!) { result, error in | |
| #expect(error == nil) | |
| #expect(result?.success == nil) | |
| #expect(result?.error?.type == .canceled) | |
| confirmed() | |
| } | |
| } | |
| } | |
| @Test(arguments: [ | |
| (GIDSignInError.hasNoAuthInKeychain.rawValue, FSIGoogleSignInErrorCode.noAuthInKeychain), | |
| (GIDSignInError.canceled.rawValue, .canceled), | |
| ]) | |
| func refreshTokensKnownErrors( | |
| errorCode: Int, | |
| expectedErrorCode: FSIGoogleSignInErrorCode | |
| ) async { | |
| let plugin = createTestPlugin() | |
| let fakeUser = addSignedInUser(to: plugin) | |
| fakeUser.error = NSError(domain: kGIDSignInErrorDomain, code: errorCode, userInfo: nil) | |
| await confirmation("completion called") { confirmed in | |
| plugin.refreshedAuthorizationTokens(forUser: fakeUser.userID!) { result, error in | |
| #expect(error == nil) | |
| #expect(result?.success == nil) | |
| #expect(result?.error?.type == expectedErrorCode) | |
| confirmed() | |
| } | |
| } | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've parameterized several sets of tests. Unfortunately we lose the helpful test names (e.g. refreshTokensNoAuthKeychainError is now refreshTokensGIDSignInErrorDomainErrors > -4, FSIGoogleSignInErrorCode(rawValue: 2)), but I don't think that's probably a big deal. If it becomes annoying we can always add an extra fake initial parameter that's the test "name".
I also did a bit more refactoring to make the test fixture fully stateless so that I could adopt suites, and group each method's tests into a suite.
This comment was marked as outdated.
This comment was marked as outdated.
| var exception: NSException? | ||
|
|
||
| // Results to use in completion callbacks. | ||
| var user: FSIGIDGoogleUser? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought FSIGIDGoogleUser is now a protocol so it is supposed to be an existential type here (any FSIGIDGoogleUser?)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, my Swift experience is still thin, and I'd missed the memo on the switch to explicit existentials in more recent versions of Swift. I think I've fixed all the cases here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. On a side note I didn't know they were planning to enforce that, created flutter/flutter#181005
|
I forgot Swift imports don't like Obj-C submodules. I'm not sure why it was failing in CI but working locally (Xcode version?) but to resolve it I just removed the modulemap, so there's no longer a distinction between test and non-test headers; this is the same thing we've had to do with some other plugins. It shouldn't actually affect anything, since nobody should be importing the native framework anyway, but also it'll be temporary since I plan to convert the plugin to Swift shortly anyway. |
|
(I did add a version bump though, since it's no longer a test-only change, even though I don't expect any client impact.) |
flutter/packages@98b0325...ce3afa4 2026-01-15 [email protected] Manual roll Flutter from 793b0b8 to b45a73b (8 revisions) (flutter/packages#10799) 2026-01-15 [email protected] [path_provider] Re-release FFI foundation version (flutter/packages#10722) 2026-01-15 [email protected] [google_sign_in] Convert iOS tests to Swift (flutter/packages#10787) 2026-01-14 [email protected] [video_player] Update for UIScene compatibility (flutter/packages#10676) 2026-01-14 [email protected] [pointer_interceptor_ios] Migrate XCTest to Swift Testing (flutter/packages#10762) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
…r#181035) flutter/packages@98b0325...ce3afa4 2026-01-15 [email protected] Manual roll Flutter from 793b0b8 to b45a73b (8 revisions) (flutter/packages#10799) 2026-01-15 [email protected] [path_provider] Re-release FFI foundation version (flutter/packages#10722) 2026-01-15 [email protected] [google_sign_in] Convert iOS tests to Swift (flutter/packages#10787) 2026-01-14 [email protected] [video_player] Update for UIScene compatibility (flutter/packages#10676) 2026-01-14 [email protected] [pointer_interceptor_ios] Migrate XCTest to Swift Testing (flutter/packages#10762) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Converts the existing native unit tests from Objective-C to Swift.
This was done as a few steps:
loadGoogleServiceInfoandcreateTestPluginhelpers, because there was no reason the test needed to be so stateful, and removing the state makes the test-specific setup easier to follow (e.g., a subset of the tests didn't actually use the test-globalplugininstance, but instead replaced it with a local copy, which made things confusing when moving between tests). It also allows adding suites.Part of flutter/flutter#119103
Part of flutter/flutter#180787
Pre-Review Checklist
[shared_preferences]pubspec.yamlwith an appropriate new version according to the pub versioning philosophy, or I have commented below to indicate which version change exemption this PR falls under1.CHANGELOG.mdto add a description of the change, following repository CHANGELOG style, or I have commented below to indicate which CHANGELOG exemption this PR falls under1.///).Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2 ↩3