From b6d68e7e7edaf4c3284d3f431a68e933666eb52f Mon Sep 17 00:00:00 2001 From: Matt Kiazyk Date: Fri, 11 Sep 2026 19:57:02 -0500 Subject: [PATCH] chore: update xcodesKit and LoginKit to latest. minor fixes --- Xcodes.xcodeproj/project.pbxproj | 6 +- .../xcshareddata/swiftpm/Package.resolved | 10 +- Xcodes/Backend/AppState.swift | 25 +++- Xcodes/Backend/Environment.swift | 8 +- .../Frontend/InfoPane/InfoPaneControls.swift | 9 ++ Xcodes/Frontend/MainWindow.swift | 18 ++- Xcodes/Frontend/XcodeList/XcodeListView.swift | 6 +- .../Frontend/XcodeList/XcodeListViewRow.swift | 14 ++- Xcodes/Resources/Licenses.rtf | 29 +---- Xcodes/Resources/Localizable.xcstrings | 118 ++++++++++++++++++ XcodesTests/AppStateTests.swift | 31 ++++- XcodesTests/Environment+Mock.swift | 2 +- 12 files changed, 226 insertions(+), 50 deletions(-) diff --git a/Xcodes.xcodeproj/project.pbxproj b/Xcodes.xcodeproj/project.pbxproj index 3ad4c327..05f49654 100644 --- a/Xcodes.xcodeproj/project.pbxproj +++ b/Xcodes.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 14d2f5a1273f6c350cad4406 /* NewVersionNotificationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884f01aed2f43048ab4d3323 /* NewVersionNotificationTests.swift */; }; 15F5B8902CCF09B900705E2F /* CryptoKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15F5B88F2CCF09B900705E2F /* CryptoKit.framework */; }; 3328073F2CA5E2C80036F691 /* SignInSecurityKeyPinView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3328073E2CA5E2C80036F691 /* SignInSecurityKeyPinView.swift */; }; 332807412CA5EA820036F691 /* SignInSecurityKeyTouchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 332807402CA5EA820036F691 /* SignInSecurityKeyTouchView.swift */; }; @@ -31,7 +32,6 @@ BDBAB7452B9FF55800694B0B /* TrailingIconLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDBAB7442B9FF55800694B0B /* TrailingIconLabelStyle.swift */; }; CA11E7BA2598476C00D2EE1C /* XcodeCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA11E7B92598476C00D2EE1C /* XcodeCommands.swift */; }; CA2518EC25A7FF2B00F08414 /* AppStateUpdateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2518EB25A7FF2B00F08414 /* AppStateUpdateTests.swift */; }; - 14d2f5a1273f6c350cad4406 /* NewVersionNotificationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884f01aed2f43048ab4d3323 /* NewVersionNotificationTests.swift */; }; CA378F992466567600A58CE0 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA378F982466567600A58CE0 /* AppState.swift */; }; CA39711924495F0E00AFFB77 /* AppStoreButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA39711824495F0E00AFFB77 /* AppStoreButtonStyle.swift */; }; CA42DD7325AEB04300BC0B0C /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA42DD7225AEB04300BC0B0C /* Logger.swift */; }; @@ -194,6 +194,7 @@ 536CFDD3263C9A8000026CE0 /* XcodesSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodesSheet.swift; sourceTree = ""; }; 53CBAB2B263DCC9100410495 /* XcodesAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodesAlert.swift; sourceTree = ""; }; 63EAA4EA259944450046AB8F /* ProgressButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressButton.swift; sourceTree = ""; }; + 884f01aed2f43048ab4d3323 /* NewVersionNotificationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewVersionNotificationTests.swift; sourceTree = ""; }; 9DD4FFCA2B13EC1800C974F1 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; B0403CEF2AD92D7B00137C09 /* ReleaseNotesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseNotesView.swift; sourceTree = ""; }; B0403CF12AD934B600137C09 /* CompatibilityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompatibilityView.swift; sourceTree = ""; }; @@ -209,7 +210,6 @@ BDBAB7442B9FF55800694B0B /* TrailingIconLabelStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrailingIconLabelStyle.swift; sourceTree = ""; }; CA11E7B92598476C00D2EE1C /* XcodeCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodeCommands.swift; sourceTree = ""; }; CA2518EB25A7FF2B00F08414 /* AppStateUpdateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStateUpdateTests.swift; sourceTree = ""; }; - 884f01aed2f43048ab4d3323 /* NewVersionNotificationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewVersionNotificationTests.swift; sourceTree = ""; }; CA378F982466567600A58CE0 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; }; CA39711824495F0E00AFFB77 /* AppStoreButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStoreButtonStyle.swift; sourceTree = ""; }; CA42DD7225AEB04300BC0B0C /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; }; @@ -1521,7 +1521,7 @@ repositoryURL = "https://github.com/XcodesOrg/XcodesKit"; requirement = { kind = upToNextMinorVersion; - minimumVersion = 1.0.4; + minimumVersion = 1.1.0; }; }; E89CBD3B2D5FC0B10037ED95 /* XCRemoteSwiftPackageReference "XcodesLoginKit" */ = { diff --git a/Xcodes.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Xcodes.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index fa02b2c6..4f9d80c0 100644 --- a/Xcodes.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Xcodes.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -51,8 +51,8 @@ "repositoryURL": "https://github.com/kinoroy/LibFido2Swift", "state": { "branch": null, - "revision": "b87a93300c5b35307c9f26ae490963196bd927f1", - "version": "0.1.5" + "revision": "ac8596a852e2b008c5902a521cf4d9c7f0f05fba", + "version": "0.1.6" } }, { @@ -123,8 +123,8 @@ "repositoryURL": "https://github.com/XcodesOrg/XcodesKit", "state": { "branch": null, - "revision": "a9e5d7d701f20f1385071851319cdaecccc9f1e8", - "version": "1.0.4" + "revision": "4d3c6093980978b74c3fa42fc1b90cd1c34ac911", + "version": "1.1.0" } }, { @@ -132,7 +132,7 @@ "repositoryURL": "https://github.com/XcodesOrg/XcodesLoginKit", "state": { "branch": "main", - "revision": "9bece1ada36006b18b84caec62d14dc91b47ae2b", + "revision": "929f9aac3140caf7b64cbb5385f4f645c5f9913d", "version": null } }, diff --git a/Xcodes/Backend/AppState.swift b/Xcodes/Backend/AppState.swift index ba6f91db..7924e649 100644 --- a/Xcodes/Backend/AppState.swift +++ b/Xcodes/Backend/AppState.swift @@ -249,6 +249,9 @@ class AppState: ObservableObject { } setupAutoInstallTimer() setupDefaults() + startAuthenticationTask { + try await self.restoreAuthenticationStateIfNeeded() + } } func setupDefaults() { @@ -286,13 +289,19 @@ class AppState: ObservableObject { ).validateADCSession(path: path) } - func validateSessionAsync() async throws { + @discardableResult + func validateSessionAsync() async throws -> AuthenticationState { try await Current.network.validateSessionAsync() } func signInIfNeededAsync() async throws { do { - try await validateSessionAsync() + let authenticationState = try await validateSessionAsync() + try Task.checkCancellation() + self.authenticationState = authenticationState + handleAuthenticationFlowSuccess() + } catch is CancellationError { + throw CancellationError() } catch { guard let username = savedUsername, @@ -305,6 +314,11 @@ class AppState: ObservableObject { } } + func restoreAuthenticationStateIfNeeded() async throws { + guard hasSavedUsername else { return } + try await signInIfNeededAsync() + } + func signIn(username: String, password: String?) { authError = nil startAuthenticationTask { @@ -681,6 +695,10 @@ class AppState: ObservableObject { func uninstall(xcode: Xcode) { guard let installedXcodePath = xcode.installedPath else { return } + if let index = allXcodes.firstIndex(where: { $0.id == xcode.id }) { + allXcodes[index].installState = .uninstalling(installedXcodePath) + } + uninstallTask?.cancel() let taskID = UUID() uninstallTaskID = taskID @@ -699,6 +717,9 @@ class AppState: ObservableObject { await updateInstalledXcodesAsync() } catch is CancellationError { } catch { + if let index = allXcodes.firstIndex(where: { $0.id == xcode.id }) { + allXcodes[index].installState = .installed(installedXcodePath) + } self.error = error self.presentedAlert = .generic(title: localizeString("Alert.Uninstall.Error.Title"), message: error.legibleLocalizedDescription) } diff --git a/Xcodes/Backend/Environment.swift b/Xcodes/Backend/Environment.swift index 47fb9420..44a1f92a 100644 --- a/Xcodes/Backend/Environment.swift +++ b/Xcodes/Backend/Environment.swift @@ -168,7 +168,7 @@ public struct Network: Sendable { downloadTaskAsync(url, saveLocation, resumeData) } - public var validateSessionAsync: @Sendable () async throws -> Void + public var validateSessionAsync: @Sendable () async throws -> AuthenticationState public var signout: @Sendable () -> Void @@ -176,7 +176,7 @@ public struct Network: Sendable { session: URLSession? = nil, loadData: (@Sendable (URLRequest) async throws -> (Data, URLResponse))? = nil, downloadTaskAsync: (@Sendable (URL, URL, Data?) -> (Progress, Task<(saveLocation: URL, response: URLResponse), Error>))? = nil, - validateSessionAsync: (@Sendable () async throws -> Void)? = nil, + validateSessionAsync: (@Sendable () async throws -> AuthenticationState)? = nil, signout: (@Sendable () -> Void)? = nil ) { let loginClient: XcodesLoginKit.Client @@ -193,7 +193,7 @@ public struct Network: Sendable { loginClient.urlSession.downloadTaskAsync(with: url, to: saveLocation, resumingWith: resumeData) } self.validateSessionAsync = validateSessionAsync ?? { - _ = try await loginClient.validateSession() + try await loginClient.validateSession() } self.signout = signout ?? { loginClient.signout() @@ -208,7 +208,7 @@ public struct Network: Sendable { loginClient.urlSession.downloadTaskAsync(with: url, to: saveLocation, resumingWith: resumeData) } self.validateSessionAsync = { - _ = try await loginClient.validateSession() + try await loginClient.validateSession() } self.signout = { loginClient.signout() diff --git a/Xcodes/Frontend/InfoPane/InfoPaneControls.swift b/Xcodes/Frontend/InfoPane/InfoPaneControls.swift index de1356ed..b1368141 100644 --- a/Xcodes/Frontend/InfoPane/InfoPaneControls.swift +++ b/Xcodes/Frontend/InfoPane/InfoPaneControls.swift @@ -30,6 +30,15 @@ struct InfoPaneControls: View { } case .installed(_): InstalledStateButtons(xcode: xcode) + case .uninstalling: + HStack { + Spacer() + ProgressView() + .scaleEffect(0.5) + Text("Uninstalling") + .font(.caption) + .foregroundStyle(.secondary) + } } } } diff --git a/Xcodes/Frontend/MainWindow.swift b/Xcodes/Frontend/MainWindow.swift index 0de18b5c..ae313aed 100644 --- a/Xcodes/Frontend/MainWindow.swift +++ b/Xcodes/Frontend/MainWindow.swift @@ -46,7 +46,16 @@ struct MainWindow: View { .toolbar { ToolbarItemGroup { Button(action: { appState.presentedSheet = .signIn }, label: { - Label("Login", systemImage: "person.circle") + Label { + if let authenticatedUserName { + Text(verbatim: authenticatedUserName) + } else { + Text("Login") + } + } icon: { + Image(systemName: "person.circle") + } + .labelStyle(.titleAndIcon) }) .help("LoginDescription") if #available(macOS 14, *) { @@ -95,6 +104,13 @@ struct MainWindow: View { appState.allXcodes.first(where: { $0.id == selectedXcodeID }) } + private var authenticatedUserName: String? { + guard case let .authenticated(appleSession) = appState.authenticationState else { + return nil + } + return appleSession.user.fullName ?? appState.savedUsername + } + private var subtitleText: Text { if let lastUpdated = lastUpdated.map(Date.init(timeIntervalSince1970:)) { return Text("\(localizeString("UpdatedAt")) \(lastUpdated, style: .date) \(lastUpdated, style: .time)") diff --git a/Xcodes/Frontend/XcodeList/XcodeListView.swift b/Xcodes/Frontend/XcodeList/XcodeListView.swift index ce75938e..12cfdb05 100644 --- a/Xcodes/Frontend/XcodeList/XcodeListView.swift +++ b/Xcodes/Frontend/XcodeList/XcodeListView.swift @@ -285,7 +285,7 @@ private struct XcodeVersionGroupRow: View { Image(systemName: "checkmark.circle.fill") .foregroundColor(.yellow) .help(staleSelectedHelpText(selectedVersion: selectedVersion, latestRelease: latestSelectableRelease, selectionTarget: latestSelectionTarget)) - case .installing, .none: + case .installing, .uninstalling, .none: EmptyView() } } else if selectedVersion?.selected == true { @@ -316,7 +316,7 @@ private struct XcodeVersionGroupRow: View { } else { return Text(verbatim: "\(selectedVersion.description) selected, \(latestRelease.description) available.") } - case .installing, .none: + case .installing, .uninstalling, .none: return Text(verbatim: "\(selectedVersion.description) selected, \(latestRelease.description) available.") } } @@ -344,7 +344,7 @@ private struct XcodeVersionGroupRow: View { .textCase(.uppercase) .buttonStyle(AppStoreButtonStyle(primary: false, highlighted: false)) .help("InstallDescription") - case .installing: + case .installing, .uninstalling: EmptyView() } } diff --git a/Xcodes/Frontend/XcodeList/XcodeListViewRow.swift b/Xcodes/Frontend/XcodeList/XcodeListViewRow.swift index 166b9d09..2d86e634 100644 --- a/Xcodes/Frontend/XcodeList/XcodeListViewRow.swift +++ b/Xcodes/Frontend/XcodeList/XcodeListViewRow.swift @@ -63,6 +63,8 @@ struct XcodeListViewRow: View { InstallButton(xcode: xcode) case .installing: CancelInstallButton(xcode: xcode) + case .uninstalling: + EmptyView() case let .installed(path): SelectButton(xcode: xcode) OpenButton(xcode: xcode) @@ -119,7 +121,7 @@ struct XcodeListViewRow: View { Image(systemName: "checkmark.circle.fill") .foregroundColor(.yellow) .help(staleSelectedHelpText) - case .installing: + case .installing, .uninstalling: EmptyView() } } else if xcode.selected { @@ -170,6 +172,14 @@ struct XcodeListViewRow: View { highlighted: selected, cancel: { appState.presentedAlert = .cancelInstall(xcode: xcode) } ) + case .uninstalling: + HStack(spacing: 4) { + ProgressView() + .scaleEffect(0.5) + Text("Uninstalling") + .font(.caption) + .foregroundStyle(.secondary) + } } } @@ -182,7 +192,7 @@ struct XcodeListViewRow: View { return Text(verbatim: "\(selectedVersion) selected, \(latestVersion) available. Click to select \(latestVersion).") case .notInstalled: return Text(verbatim: "\(selectedVersion) selected, \(latestVersion) available. Install \(latestVersion) to select it.") - case .installing, .none: + case .installing, .uninstalling, .none: return Text("ActiveVersionDescription") } } diff --git a/Xcodes/Resources/Licenses.rtf b/Xcodes/Resources/Licenses.rtf index 1687a178..9cf2e752 100644 --- a/Xcodes/Resources/Licenses.rtf +++ b/Xcodes/Resources/Licenses.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2869 +{\rtf1\ansi\ansicpg1252\cocoartf2870 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 .SFNS-Regular;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} @@ -1090,33 +1090,6 @@ SOFTWARE.\ \ \ -\fs34 data\ -\ - -\fs26 MIT License\ -\ -Copyright (c) 2018 \ -\ -Permission is hereby granted, free of charge, to any person obtaining a copy\ -of this software and associated documentation files (the "Software"), to deal\ -in the Software without restriction, including without limitation the rights\ -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ -copies of the Software, and to permit persons to whom the Software is\ -furnished to do so, subject to the following conditions:\ -\ -The above copyright notice and this permission notice shall be included in all\ -copies or substantial portions of the Software.\ -\ -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\ -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\ -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\ -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\ -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\ -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\ -SOFTWARE.\ -\ -\ - \fs34 Sparkle\ \ diff --git a/Xcodes/Resources/Localizable.xcstrings b/Xcodes/Resources/Localizable.xcstrings index 0716fee2..93e638da 100644 --- a/Xcodes/Resources/Localizable.xcstrings +++ b/Xcodes/Resources/Localizable.xcstrings @@ -24937,6 +24937,124 @@ } } }, + "Uninstalling" : { + "localizations" : { + "ca" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desinstal·lant" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deinstallieren" + } + }, + "el" : { + "stringUnit" : { + "state" : "translated", + "value" : "Απεγκατάσταση" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uninstalling" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desinstalando" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Poistetaan" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Désinstallation en cours" + } + }, + "hi" : { + "stringUnit" : { + "state" : "translated", + "value" : "अनइंस्टॉल हो रहा है" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Disinstallazione in corso" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "アンインストール中" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "제거 중" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bezig met verwijderen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Odinstalowywanie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desinstalando" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Удаление" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kaldırılıyor" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Видалення" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "正在卸载" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "正在解除安裝" + } + } + } + }, "Universal" : { "extractionState" : "stale", "localizations" : { diff --git a/XcodesTests/AppStateTests.swift b/XcodesTests/AppStateTests.swift index ff0a668d..f1f0000a 100644 --- a/XcodesTests/AppStateTests.swift +++ b/XcodesTests/AppStateTests.swift @@ -336,6 +336,35 @@ class AppStateTests: XCTestCase { XCTAssertTrue(Current.network.loginClient.urlSession === replacementSession) } + func test_RestoreAuthenticationStateIfNeeded_UsesPersistedSession() async throws { + let appleSession = try JSONDecoder().decode( + AppleSession.self, + from: Data(#"{"user":{"fullName":"Jane Developer"}}"#.utf8) + ) + let expectedState = AuthenticationState.authenticated(appleSession) + Current.defaults.string = { key in + key == "username" ? "jane@example.com" : nil + } + Current.network.validateSessionAsync = { expectedState } + + try await subject.restoreAuthenticationStateIfNeeded() + + XCTAssertEqual(subject.authenticationState, expectedState) + } + + func test_RestoreAuthenticationStateIfNeeded_SkipsValidationWithoutSavedUsername() async throws { + let didValidate = TestLockedBox(false) + Current.network.validateSessionAsync = { + didValidate.withValue { $0 = true } + return .unauthenticated + } + + try await subject.restoreAuthenticationStateIfNeeded() + + XCTAssertFalse(didValidate.read { $0 }) + XCTAssertEqual(subject.authenticationState, .unauthenticated) + } + func test_DownloadRuntimeViaXcodeBuild_ClearsRuntimeTaskWhenComplete() async throws { let runtime = try Self.downloadableRuntime() subject.downloadableRuntimes = [runtime] @@ -599,7 +628,7 @@ class AppStateTests: XCTestCase { return true } } - Xcodes.Current.network.validateSessionAsync = { } + Xcodes.Current.network.validateSessionAsync = { .unauthenticated } Xcodes.Current.network.loadData = { urlRequest in if urlRequest.url! == URLRequest.developerDownloads.url! { let downloads = Downloads(resultCode: 0, resultsString: nil, downloads: [Download(name: "Xcode 0.0.0", files: [Download.File(remotePath: "https://apple.com/xcode.xip", fileSize: 9484444)], dateModified: Date())]) diff --git a/XcodesTests/Environment+Mock.swift b/XcodesTests/Environment+Mock.swift index 6f351ce1..6bcf95f9 100644 --- a/XcodesTests/Environment+Mock.swift +++ b/XcodesTests/Environment+Mock.swift @@ -81,7 +81,7 @@ extension Network { } ) }, - validateSessionAsync: { }, + validateSessionAsync: { .unauthenticated }, signout: { } ) }