diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-AlertsAndConfirmationDialogsTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-AlertsAndConfirmationDialogsTests.swift index 1420b8c530f2..55d760f4316d 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-AlertsAndConfirmationDialogsTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-AlertsAndConfirmationDialogsTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class AlertsAndConfirmationDialogsTests: XCTestCase { + @MainActor func testAlert() async { let store = TestStore(initialState: AlertAndConfirmationDialog.State()) { AlertAndConfirmationDialog() @@ -33,6 +33,7 @@ final class AlertsAndConfirmationDialogsTests: XCTestCase { } } + @MainActor func testConfirmationDialog() async { let store = TestStore(initialState: AlertAndConfirmationDialog.State()) { AlertAndConfirmationDialog() diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-AnimationsTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-AnimationsTests.swift index 856812c159ad..8420761b5f40 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-AnimationsTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-AnimationsTests.swift @@ -4,8 +4,8 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class AnimationTests: XCTestCase { + @MainActor func testRainbow() async { let clock = TestClock() @@ -58,6 +58,7 @@ final class AnimationTests: XCTestCase { await clock.run() } + @MainActor func testReset() async { let clock = TestClock() diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-BindingBasicsTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-BindingBasicsTests.swift index 6d252f3fcb57..6e42fd44801f 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-BindingBasicsTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-BindingBasicsTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class BindingFormTests: XCTestCase { + @MainActor func testBasics() async { let store = TestStore(initialState: BindingForm.State()) { BindingForm() diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-SharedStateTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-SharedStateTests.swift index 2f33466c57e4..17aa0b50376f 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-SharedStateTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/01-GettingStarted-SharedStateTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class SharedStateTests: XCTestCase { + @MainActor func testTabSelection() async { let store = TestStore(initialState: SharedState.State()) { SharedState() @@ -18,6 +18,7 @@ final class SharedStateTests: XCTestCase { } } + @MainActor func testSharedCounts() async { let store = TestStore(initialState: SharedState.State()) { SharedState() @@ -37,6 +38,7 @@ final class SharedStateTests: XCTestCase { } } + @MainActor func testAlert() async { let store = TestStore(initialState: SharedState.State()) { SharedState() diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-BasicsTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-BasicsTests.swift index c272c1dd4c32..0acda84c7322 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-BasicsTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-BasicsTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class EffectsBasicsTests: XCTestCase { + @MainActor func testCountDown() async { let store = TestStore(initialState: EffectsBasics.State()) { EffectsBasics() @@ -20,6 +20,7 @@ final class EffectsBasicsTests: XCTestCase { } } + @MainActor func testNumberFact() async { let store = TestStore(initialState: EffectsBasics.State()) { EffectsBasics() @@ -40,6 +41,7 @@ final class EffectsBasicsTests: XCTestCase { } } + @MainActor func testDecrement() async { let store = TestStore(initialState: EffectsBasics.State()) { EffectsBasics() @@ -55,6 +57,7 @@ final class EffectsBasicsTests: XCTestCase { } } + @MainActor func testDecrementCancellation() async { let store = TestStore(initialState: EffectsBasics.State()) { EffectsBasics() diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-CancellationTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-CancellationTests.swift index 8414215e760a..208d220be606 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-CancellationTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-CancellationTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class EffectsCancellationTests: XCTestCase { + @MainActor func testTrivia_SuccessfulRequest() async { let store = TestStore(initialState: EffectsCancellation.State()) { EffectsCancellation() @@ -27,6 +27,7 @@ final class EffectsCancellationTests: XCTestCase { } } + @MainActor func testTrivia_FailedRequest() async { struct FactError: Equatable, Error {} let store = TestStore(initialState: EffectsCancellation.State()) { @@ -49,6 +50,7 @@ final class EffectsCancellationTests: XCTestCase { // in the `.cancelButtonTapped` action of the `effectsCancellationReducer`. This will cause the // test to fail, showing that we are exhaustively asserting that the effect truly is canceled and // will never emit. + @MainActor func testTrivia_CancelButtonCancelsRequest() async { let store = TestStore(initialState: EffectsCancellation.State()) { EffectsCancellation() @@ -64,6 +66,7 @@ final class EffectsCancellationTests: XCTestCase { } } + @MainActor func testTrivia_PlusMinusButtonsCancelsRequest() async { let store = TestStore(initialState: EffectsCancellation.State()) { EffectsCancellation() diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-LongLivingTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-LongLivingTests.swift index 9d969b393940..3278f0b24d0d 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-LongLivingTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-LongLivingTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class LongLivingEffectsTests: XCTestCase { + @MainActor func testReducer() async { let (screenshots, takeScreenshot) = AsyncStream.makeStream(of: Void.self) diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-RefreshableTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-RefreshableTests.swift index 98a8d0be8e8b..d216d0e25c43 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-RefreshableTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-RefreshableTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class RefreshableTests: XCTestCase { + @MainActor func testHappyPath() async { let store = TestStore(initialState: Refreshable.State()) { Refreshable() @@ -22,6 +22,7 @@ final class RefreshableTests: XCTestCase { } } + @MainActor func testUnhappyPath() async { struct FactError: Equatable, Error {} @@ -39,6 +40,7 @@ final class RefreshableTests: XCTestCase { await store.receive(\.factResponse.failure) } + @MainActor func testCancellation() async { let store = TestStore(initialState: Refreshable.State()) { Refreshable() diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-TimersTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-TimersTests.swift index 7e5f4ac17b7e..c6aaf310ea66 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-TimersTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-TimersTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class TimersTests: XCTestCase { + @MainActor func testStart() async { let clock = TestClock() diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-WebSocketTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-WebSocketTests.swift index 4dffea08df53..e3eff0fd5b04 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-WebSocketTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-WebSocketTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class WebSocketTests: XCTestCase { + @MainActor func testWebSocketHappyPath() async { let actions = AsyncStream.makeStream(of: WebSocketClient.Action.self) let messages = AsyncStream.makeStream(of: Result.self) @@ -56,6 +56,7 @@ final class WebSocketTests: XCTestCase { await store.finish() } + @MainActor func testWebSocketSendFailure() async { let actions = AsyncStream.makeStream(of: WebSocketClient.Action.self) let messages = AsyncStream.makeStream(of: Result.self) @@ -102,6 +103,7 @@ final class WebSocketTests: XCTestCase { await store.finish() } + @MainActor func testWebSocketPings() async { let actions = AsyncStream.makeStream(of: WebSocketClient.Action.self) let clock = TestClock() @@ -136,6 +138,7 @@ final class WebSocketTests: XCTestCase { } } + @MainActor func testWebSocketConnectError() async { let actions = AsyncStream.makeStream(of: WebSocketClient.Action.self) diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-RecursionTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-RecursionTests.swift index 2e194b120a9a..d6c5269da554 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-RecursionTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-RecursionTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class RecursionTests: XCTestCase { + @MainActor func testAddRow() async { let store = TestStore(initialState: Nested.State(id: UUID())) { Nested() @@ -21,6 +21,7 @@ final class RecursionTests: XCTestCase { } } + @MainActor func testChangeName() async { let store = TestStore(initialState: Nested.State(id: UUID())) { Nested() @@ -31,6 +32,7 @@ final class RecursionTests: XCTestCase { } } + @MainActor func testDeleteRow() async { let store = TestStore( initialState: Nested.State( diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-ReusableFavoritingTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-ReusableFavoritingTests.swift index fe91641ffe91..df1b73a13a34 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-ReusableFavoritingTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-ReusableFavoritingTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class ReusableComponentsFavoritingTests: XCTestCase { + @MainActor func testHappyPath() async { let clock = TestClock() @@ -50,6 +50,7 @@ final class ReusableComponentsFavoritingTests: XCTestCase { await store.receive(\.episodes[id:episodes[1].id].favorite.response.success) } + @MainActor func testUnhappyPath() async { let episodes: IdentifiedArrayOf = [ Episode.State( diff --git a/Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift b/Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift index 11a2b104957a..fdfdfe8012cf 100644 --- a/Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift +++ b/Examples/CaseStudies/SwiftUICaseStudiesTests/04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift @@ -3,11 +3,10 @@ import XCTest @testable import SwiftUICaseStudies -@MainActor final class ReusableComponentsDownloadComponentTests: XCTestCase { - let download = AsyncThrowingStream.makeStream(of: DownloadClient.Event.self) - + @MainActor func testDownloadFlow() async { + let download = AsyncThrowingStream.makeStream(of: DownloadClient.Event.self) let store = TestStore( initialState: DownloadComponent.State( id: 1, @@ -17,26 +16,28 @@ final class ReusableComponentsDownloadComponentTests: XCTestCase { ) { DownloadComponent() } withDependencies: { - $0.downloadClient.download = { @Sendable _ in self.download.stream } + $0.downloadClient.download = { @Sendable _ in download.stream } } await store.send(.buttonTapped) { $0.mode = .startingToDownload } - self.download.continuation.yield(.updateProgress(0.2)) + download.continuation.yield(.updateProgress(0.2)) await store.receive(\.downloadClient.success.updateProgress) { $0.mode = .downloading(progress: 0.2) } - self.download.continuation.yield(.response(Data())) - self.download.continuation.finish() + download.continuation.yield(.response(Data())) + download.continuation.finish() await store.receive(\.downloadClient.success.response) { $0.mode = .downloaded } } + @MainActor func testCancelDownloadFlow() async { + let download = AsyncThrowingStream.makeStream(of: DownloadClient.Event.self) let store = TestStore( initialState: DownloadComponent.State( id: 1, @@ -46,14 +47,14 @@ final class ReusableComponentsDownloadComponentTests: XCTestCase { ) { DownloadComponent() } withDependencies: { - $0.downloadClient.download = { @Sendable _ in self.download.stream } + $0.downloadClient.download = { @Sendable _ in download.stream } } await store.send(.buttonTapped) { $0.mode = .startingToDownload } - self.download.continuation.yield(.updateProgress(0.2)) + download.continuation.yield(.updateProgress(0.2)) await store.receive(\.downloadClient.success.updateProgress) { $0.mode = .downloading(progress: 0.2) } @@ -77,7 +78,9 @@ final class ReusableComponentsDownloadComponentTests: XCTestCase { } } + @MainActor func testDownloadFinishesWhileTryingToCancel() async { + let download = AsyncThrowingStream.makeStream(of: DownloadClient.Event.self) let store = TestStore( initialState: DownloadComponent.State( id: 1, @@ -87,7 +90,7 @@ final class ReusableComponentsDownloadComponentTests: XCTestCase { ) { DownloadComponent() } withDependencies: { - $0.downloadClient.download = { @Sendable _ in self.download.stream } + $0.downloadClient.download = { @Sendable _ in download.stream } } let task = await store.send(.buttonTapped) { @@ -107,8 +110,8 @@ final class ReusableComponentsDownloadComponentTests: XCTestCase { } } - self.download.continuation.yield(.response(Data())) - self.download.continuation.finish() + download.continuation.yield(.response(Data())) + download.continuation.finish() await store.receive(\.downloadClient.success.response) { $0.alert = nil $0.mode = .downloaded @@ -117,7 +120,9 @@ final class ReusableComponentsDownloadComponentTests: XCTestCase { await task.finish() } + @MainActor func testDeleteDownloadFlow() async { + let download = AsyncThrowingStream.makeStream(of: DownloadClient.Event.self) let store = TestStore( initialState: DownloadComponent.State( id: 1, @@ -127,7 +132,7 @@ final class ReusableComponentsDownloadComponentTests: XCTestCase { ) { DownloadComponent() } withDependencies: { - $0.downloadClient.download = { @Sendable _ in self.download.stream } + $0.downloadClient.download = { @Sendable _ in download.stream } } await store.send(.buttonTapped) { diff --git a/Examples/CaseStudies/UIKitCaseStudiesTests/UIKitCaseStudiesTests.swift b/Examples/CaseStudies/UIKitCaseStudiesTests/UIKitCaseStudiesTests.swift index f2d540889fb2..64dcaa9b36ff 100644 --- a/Examples/CaseStudies/UIKitCaseStudiesTests/UIKitCaseStudiesTests.swift +++ b/Examples/CaseStudies/UIKitCaseStudiesTests/UIKitCaseStudiesTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import UIKitCaseStudies -@MainActor final class UIKitCaseStudiesTests: XCTestCase { + @MainActor func testCountDown() async { let store = TestStore(initialState: Counter.State()) { Counter() @@ -18,6 +18,7 @@ final class UIKitCaseStudiesTests: XCTestCase { } } + @MainActor func testCountDownList() async { let firstState = Counter.State() let secondState = Counter.State() diff --git a/Examples/CaseStudies/tvOSCaseStudiesTests/FocusTests.swift b/Examples/CaseStudies/tvOSCaseStudiesTests/FocusTests.swift index e84fb13a4686..af3c5156c5c0 100644 --- a/Examples/CaseStudies/tvOSCaseStudiesTests/FocusTests.swift +++ b/Examples/CaseStudies/tvOSCaseStudiesTests/FocusTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import tvOSCaseStudies -@MainActor final class tvOSCaseStudiesTests: XCTestCase { + @MainActor func testFocus() async { let store = TestStore(initialState: Focus.State(currentFocus: 1)) { Focus() diff --git a/Examples/Integration/IntegrationUITests/Internal/BaseIntegrationTests.swift b/Examples/Integration/IntegrationUITests/Internal/BaseIntegrationTests.swift index bfae1b2683b3..da47d31d9daf 100644 --- a/Examples/Integration/IntegrationUITests/Internal/BaseIntegrationTests.swift +++ b/Examples/Integration/IntegrationUITests/Internal/BaseIntegrationTests.swift @@ -1,10 +1,10 @@ import Accessibility import CustomDump -import InlineSnapshotTesting +@preconcurrency import InlineSnapshotTesting import XCTest -@MainActor class BaseIntegrationTests: XCTestCase { + @MainActor var app: XCUIApplication! var logs: XCUIElement! private var _expectRuntimeWarnings: (file: StaticString, line: UInt)? @@ -13,8 +13,9 @@ class BaseIntegrationTests: XCTestCase { self._expectRuntimeWarnings = (file, line) } + @MainActor override func setUp() async throws { - //SnapshotTesting.isRecording = true + // SnapshotTesting.isRecording = true // self.continueAfterFailure = false self.app = XCUIApplication() self.app.launchEnvironment["UI_TEST"] = "true" @@ -23,6 +24,7 @@ class BaseIntegrationTests: XCTestCase { self.logs = self.app.staticTexts["composable-architecture.debug.logs"] } + @MainActor override func tearDown() { super.tearDown() if let (file, line) = self._expectRuntimeWarnings { @@ -41,6 +43,7 @@ class BaseIntegrationTests: XCTestCase { SnapshotTesting.isRecording = false } + @MainActor func clearLogs() { DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { let alert = XCUIApplication(bundleIdentifier: "com.apple.springboard").alerts @@ -54,6 +57,7 @@ class BaseIntegrationTests: XCTestCase { XCUIDevice.shared.system.open(URL(string: "integration:///clear-logs")!) } + @MainActor func assertLogs( _ logConfiguration: LogConfiguration = .unordered, matches expectedLogs: (() -> String)? = nil, @@ -88,7 +92,7 @@ enum LogConfiguration { } extension Snapshotting where Value == String, Format == String { - fileprivate static let _lines = Snapshotting( + fileprivate static nonisolated(unsafe) let _lines = Snapshotting( pathExtension: "txt", diffing: Diffing( toData: { Data($0.utf8) }, diff --git a/Examples/Integration/IntegrationUITests/Legacy/BindingLocalTests.swift b/Examples/Integration/IntegrationUITests/Legacy/BindingLocalTests.swift index aae1a60c6aff..aa93712d8c21 100644 --- a/Examples/Integration/IntegrationUITests/Legacy/BindingLocalTests.swift +++ b/Examples/Integration/IntegrationUITests/Legacy/BindingLocalTests.swift @@ -1,8 +1,8 @@ import TestCases import XCTest -@MainActor final class BindingLocalTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try XCTSkipIf(ProcessInfo.processInfo.environment["CI"] != nil) try super.setUpWithError() @@ -10,6 +10,7 @@ final class BindingLocalTests: BaseIntegrationTests { app.collectionViews.buttons[TestCase.bindingLocal.rawValue].tap() } + @MainActor func testNoBindingWarning_FullScreenCover() { app.buttons["Full-screen-cover"].tap() @@ -18,6 +19,7 @@ final class BindingLocalTests: BaseIntegrationTests { app.buttons["Dismiss"].tap() } + @MainActor func testOnDisappearWarning_FullScreenCover() { self.expectRuntimeWarnings() @@ -30,6 +32,7 @@ final class BindingLocalTests: BaseIntegrationTests { app.buttons["Dismiss"].tap() } + @MainActor func testNoBindingWarning_NavigationDestination() { app.buttons["Navigation destination"].tap() @@ -38,6 +41,7 @@ final class BindingLocalTests: BaseIntegrationTests { app.buttons["Dismiss"].tap() } + @MainActor func testOnDisappearWarning_NavigationDestination() { self.expectRuntimeWarnings() @@ -50,6 +54,7 @@ final class BindingLocalTests: BaseIntegrationTests { app.buttons["Dismiss"].tap() } + @MainActor func testNoBindingWarning_Path() { app.buttons["Path"].tap() @@ -58,6 +63,7 @@ final class BindingLocalTests: BaseIntegrationTests { app.buttons["Dismiss"].tap() } + @MainActor func testOnDisappearWarning_Path() { self.expectRuntimeWarnings() @@ -70,6 +76,7 @@ final class BindingLocalTests: BaseIntegrationTests { app.buttons["Dismiss"].tap() } + @MainActor func testNoBindingWarning_Popover() { app.buttons["Popover"].tap() @@ -78,6 +85,7 @@ final class BindingLocalTests: BaseIntegrationTests { app.buttons["Dismiss"].tap() } + @MainActor func testOnDisappearWarning_Popover() { self.expectRuntimeWarnings() @@ -90,6 +98,7 @@ final class BindingLocalTests: BaseIntegrationTests { app.buttons["Dismiss"].tap() } + @MainActor func testNoBindingWarning_Sheet() { app.buttons["Sheet"].tap() @@ -98,6 +107,7 @@ final class BindingLocalTests: BaseIntegrationTests { app.buttons["Dismiss"].tap() } + @MainActor func testOnDisappearWarning_Sheet() { self.expectRuntimeWarnings() diff --git a/Examples/Integration/IntegrationUITests/Legacy/EscapedWithViewStoreTests.swift b/Examples/Integration/IntegrationUITests/Legacy/EscapedWithViewStoreTests.swift index 1d93fc249a42..f45bc148f540 100644 --- a/Examples/Integration/IntegrationUITests/Legacy/EscapedWithViewStoreTests.swift +++ b/Examples/Integration/IntegrationUITests/Legacy/EscapedWithViewStoreTests.swift @@ -2,14 +2,15 @@ import Integration import TestCases import XCTest -@MainActor final class EscapedWithViewStoreTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try super.setUpWithError() self.app.buttons["Legacy"].tap() app.collectionViews.buttons[TestCase.escapedWithViewStore.rawValue].tap() } + @MainActor func testExample() async throws { XCTAssertEqual(app.staticTexts["Label"].value as? String, "10") XCTAssertEqual(app.staticTexts["EscapedLabel"].value as? String, "10") diff --git a/Examples/Integration/IntegrationUITests/Legacy/ForEachBindingTests.swift b/Examples/Integration/IntegrationUITests/Legacy/ForEachBindingTests.swift index 28e196e6a8a7..9e44a18f1d18 100644 --- a/Examples/Integration/IntegrationUITests/Legacy/ForEachBindingTests.swift +++ b/Examples/Integration/IntegrationUITests/Legacy/ForEachBindingTests.swift @@ -1,14 +1,15 @@ import TestCases import XCTest -@MainActor final class ForEachBindingTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try super.setUpWithError() self.app.buttons["Legacy"].tap() app.collectionViews.buttons[TestCase.forEachBinding.rawValue].tap() } + @MainActor func testExample() async throws { app.buttons["Remove last"].tap() XCTAssertFalse(app.textFields["C"].exists) diff --git a/Examples/Integration/IntegrationUITests/Legacy/IfLetStoreTests.swift b/Examples/Integration/IntegrationUITests/Legacy/IfLetStoreTests.swift index 526f6a63af92..e6131cf3d4b8 100644 --- a/Examples/Integration/IntegrationUITests/Legacy/IfLetStoreTests.swift +++ b/Examples/Integration/IntegrationUITests/Legacy/IfLetStoreTests.swift @@ -1,14 +1,15 @@ import TestCases import XCTest -@MainActor final class IfLetStoreTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try super.setUpWithError() self.app.buttons["Legacy"].tap() self.app.buttons[TestCase.ifLetStore.rawValue].tap() } + @MainActor func testBasics() async throws { XCTAssertEqual( self.app.buttons["Show"].waitForExistence(timeout: 1), diff --git a/Examples/Integration/IntegrationUITests/Legacy/LegacyNavigationTests.swift b/Examples/Integration/IntegrationUITests/Legacy/LegacyNavigationTests.swift index c9b4e4c45e70..a12be25c6b86 100644 --- a/Examples/Integration/IntegrationUITests/Legacy/LegacyNavigationTests.swift +++ b/Examples/Integration/IntegrationUITests/Legacy/LegacyNavigationTests.swift @@ -2,14 +2,15 @@ import Integration import TestCases import XCTest -@MainActor final class LegacyNavigationTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try super.setUpWithError() self.app.buttons["Legacy"].tap() self.app.buttons[TestCase.navigationStack.rawValue].tap() } + @MainActor func testChildLogic() { self.app.buttons["Go to counter"].tap() XCTAssertEqual(self.app.staticTexts["0"].exists, true) @@ -19,6 +20,7 @@ final class LegacyNavigationTests: BaseIntegrationTests { XCTAssertEqual(self.app.staticTexts["0"].exists, true) } + @MainActor func testPushAndDismiss() { XCTAssertEqual(self.app.staticTexts["Root"].exists, true) self.app.buttons["Go to counter"].tap() @@ -41,6 +43,7 @@ final class LegacyNavigationTests: BaseIntegrationTests { XCTAssertEqual(self.app.staticTexts["Root"].find().exists, true) } + @MainActor func testPopToRoot() { XCTAssertEqual(self.app.staticTexts["Root"].exists, true) self.app.buttons["Go to counter"].tap() @@ -59,6 +62,7 @@ final class LegacyNavigationTests: BaseIntegrationTests { XCTAssertEqual(self.app.staticTexts["Root"].exists, true) } + @MainActor func testChildEffectsCancelOnDismiss() { self.app.buttons["Go to counter"].tap() self.app.buttons["Run effect"].tap() @@ -69,6 +73,7 @@ final class LegacyNavigationTests: BaseIntegrationTests { ) } + @MainActor func testChildViewIdentity() { self.app.buttons["Go to counter"].tap() XCTAssertEqual(self.app.staticTexts["Has appeared"].exists, true) @@ -76,6 +81,7 @@ final class LegacyNavigationTests: BaseIntegrationTests { XCTAssertEqual(self.app.staticTexts["Has appeared"].exists, true) } + @MainActor func testSimultaneousDismissAlertAndPop() async throws { self.app.buttons["Go to counter"].tap() self.app.buttons["Show alert"].tap() @@ -85,6 +91,7 @@ final class LegacyNavigationTests: BaseIntegrationTests { try await Task.sleep(for: .seconds(1)) } + @MainActor func testNavigationDestination() async throws { self.app.buttons["Go to counter"].tap() self.app.buttons["Open navigation destination"].tap() diff --git a/Examples/Integration/IntegrationUITests/Legacy/LegacyPresentationTests.swift b/Examples/Integration/IntegrationUITests/Legacy/LegacyPresentationTests.swift index b97cd77db543..d788173649ad 100644 --- a/Examples/Integration/IntegrationUITests/Legacy/LegacyPresentationTests.swift +++ b/Examples/Integration/IntegrationUITests/Legacy/LegacyPresentationTests.swift @@ -2,14 +2,15 @@ import Integration import TestCases import XCTest -@MainActor final class LegacyPresentationTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try super.setUpWithError() self.app.buttons["Legacy"].tap() self.app.buttons[TestCase.presentation.rawValue].tap() } + @MainActor func testSheet_ChildDismiss() { self.app.buttons["Open sheet"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -26,6 +27,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testSheet_ParentDismiss() { self.app.buttons["Open sheet"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -37,6 +39,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testSheet_EffectsCancelOnDismiss() { self.app.buttons["Open sheet"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -58,6 +61,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testSheet_IdentityChange() { self.app.buttons["Open sheet"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -74,6 +78,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testPopover_ChildDismiss() { self.app.buttons["Open popover"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -90,6 +95,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testPopover_ParentDismiss() { self.app.buttons["Open popover"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -101,6 +107,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testPopover_EffectsCancelOnDismiss() { self.app.buttons["Open popover"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -122,6 +129,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testFullScreenCover_ChildDismiss() { self.app.buttons["Open full screen cover"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -138,6 +146,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testFullScreenCover_ParentDismiss() { self.app.buttons["Open full screen cover"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -149,6 +158,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testFullScreenCover_EffectsCancelOnDismiss() { self.app.buttons["Open full screen cover"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -170,6 +180,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testAlertActionDoesNotSendExtraDismiss() { self.app.buttons["Open alert"].tap() self.app.buttons["OK"].tap() @@ -179,6 +190,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testAlertCancel() { self.app.buttons["Open alert"].tap() self.app.buttons["Cancel"].tap() @@ -188,6 +200,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testAlertThenAlert() { self.app.buttons["Open alert"].tap() self.app.buttons["Show alert"].tap() @@ -197,6 +210,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testAlertThenDialog() { self.app.buttons["Open alert"].tap() self.app.buttons["Show dialog"].tap() @@ -206,6 +220,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testAlertThenSheet() { self.app.buttons["Open alert"].tap() self.app.buttons["Show sheet"].tap() @@ -215,6 +230,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testDialogActionDoesNotSendExtraDismiss() { self.app.buttons["Open dialog"].tap() self.app.buttons["OK"].tap() @@ -224,6 +240,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testDialogCancel() { self.app.buttons["Open dialog"].tap() self.app.buttons["Cancel"].tap() @@ -233,6 +250,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testShowDialogThenAlert() { self.app.buttons["Open dialog"].tap() self.app.buttons["Show alert"].tap() @@ -242,6 +260,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testShowDialogThenDialog() { self.app.buttons["Open dialog"].tap() self.app.buttons["Show dialog"].tap() @@ -251,6 +270,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testSheetExtraBindingActionsIgnoredOnDismiss() { self.app.buttons["Open sheet"].tap() self.app.textFields["Text field"].tap() @@ -261,6 +281,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testPopoverExtraBindingActionsIgnoredOnDismiss() { self.app.buttons["Open popover"].tap() self.app.textFields["Text field"].tap() @@ -271,6 +292,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testCoverExtraBindingActionsIgnoredOnDismiss() { self.app.buttons["Open full screen cover"].tap() self.app.textFields["Text field"].tap() @@ -281,6 +303,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testNavigationLink_ChildActions() { self.app.buttons["Open navigation link demo"].tap() self.app.buttons["Open navigation link"].find().tap() @@ -292,6 +315,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testNavigationLink_ChildDismiss() { self.app.buttons["Open navigation link demo"].tap() self.app.buttons["Open navigation link"].find().tap() @@ -302,6 +326,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testNavigationLink_ParentDismiss() { self.app.buttons["Open navigation link demo"].tap() self.app.buttons["Open navigation link"].find().tap() @@ -312,6 +337,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testNavigationLink_ChildEffectCancellation() { self.app.buttons["Open navigation link demo"].tap() self.app.buttons["Open navigation link"].find().tap() @@ -324,6 +350,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testNavigationLink_ExtraBindingActionsIgnoredOnDismiss() { self.app.buttons["Open navigation link demo"].tap() self.app.buttons["Open navigation link"].find().tap() @@ -332,6 +359,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { XCTAssertEqual(self.app.staticTexts["Action sent while state nil."].exists, false) } + @MainActor func testIdentifiedNavigationLink_ChildActions() { self.app.buttons["Open navigation link demo"].tap() self.app.buttons["Open identified navigation link"].find().tap() @@ -340,12 +368,14 @@ final class LegacyPresentationTests: BaseIntegrationTests { XCTAssertEqual(self.app.staticTexts["Count: 1"].exists, true) } + @MainActor func testIdentifiedNavigationLink_NonDeadbeefLink() { self.app.buttons["Open navigation link demo"].tap() self.app.buttons["Open non-deadbeef identified navigation link"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, false) } + @MainActor func testNavigationDestination_ChildDismiss() { self.app.buttons["Open navigation destination"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -362,6 +392,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testNavigationDestination_ParentDismiss() { self.app.buttons["Open navigation destination"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -373,6 +404,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { ) } + @MainActor func testNavigationDestination_BackButtonDismiss() { self.app.buttons["Open navigation destination"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -384,6 +416,7 @@ final class LegacyPresentationTests: BaseIntegrationTests { XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) } + @MainActor func testNavigationDestination_EffectsCancelOnDismiss() { self.app.buttons["Open navigation destination"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) @@ -400,24 +433,26 @@ final class LegacyPresentationTests: BaseIntegrationTests { self.app.buttons["Open navigation destination"].tap() XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) XCTAssertEqual( - self.app.staticTexts["Count: 999"].waitForExistence(timeout: 3), + app.staticTexts["Count: 999"].waitForExistence(timeout: 3), false ) } + @MainActor func testCustomAlert() { - self.app.buttons["Open custom alert"].tap() - XCTAssertEqual(self.app.staticTexts["Custom alert!"].exists, true) - self.app.typeText("Hello!") - self.app.buttons["Submit"].tap() - XCTAssertEqual(self.app.staticTexts["Hello!"].waitForExistence(timeout: 1), true) - XCTAssertEqual(self.app.staticTexts["Dismiss action sent"].waitForExistence(timeout: 1), true) + app.buttons["Open custom alert"].tap() + XCTAssertEqual(app.staticTexts["Custom alert!"].exists, true) + app.typeText("Hello!") + app.buttons["Submit"].tap() + XCTAssertEqual(app.staticTexts["Hello!"].waitForExistence(timeout: 1), true) + XCTAssertEqual(app.staticTexts["Dismiss action sent"].waitForExistence(timeout: 1), true) } + @MainActor func testDismissAndAlert() { - self.app.buttons["Open sheet"].tap() - XCTAssertEqual(self.app.staticTexts["Count: 0"].exists, true) - self.app.buttons["Dismiss and alert"].tap() + app.buttons["Open sheet"].tap() + XCTAssertEqual(app.staticTexts["Count: 0"].exists, true) + app.buttons["Dismiss and alert"].tap() XCTTODO( """ This test should pass but does not due to a SwiftUI bug. You cannot simultaneously close diff --git a/Examples/Integration/IntegrationUITests/Legacy/SwitchStoreTests.swift b/Examples/Integration/IntegrationUITests/Legacy/SwitchStoreTests.swift index cc53364fdef1..30d560802bb7 100644 --- a/Examples/Integration/IntegrationUITests/Legacy/SwitchStoreTests.swift +++ b/Examples/Integration/IntegrationUITests/Legacy/SwitchStoreTests.swift @@ -2,16 +2,17 @@ import Integration import TestCases import XCTest -@MainActor final class SwitchStoreTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try super.setUpWithError() - self.app.buttons["Legacy"].tap() + app.buttons["Legacy"].tap() app.collectionViews.buttons[TestCase.switchStore.rawValue].tap() } + @MainActor func testExample() async throws { - self.expectRuntimeWarnings() + expectRuntimeWarnings() XCTAssertFalse( app.staticTexts diff --git a/Examples/Integration/IntegrationUITests/iOS 16+17/NewContainsOldTests.swift b/Examples/Integration/IntegrationUITests/iOS 16+17/NewContainsOldTests.swift index 731517491cc6..634b7e79ec14 100644 --- a/Examples/Integration/IntegrationUITests/iOS 16+17/NewContainsOldTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 16+17/NewContainsOldTests.swift @@ -2,16 +2,17 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS16_17_NewContainsOldTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 16 + 17"].tap() self.app.buttons["New containing old"].tap() self.clearLogs() - //SnapshotTesting.isRecording = true + // SnapshotTesting.isRecording = true } + @MainActor func testIncrementDecrement() { self.app.buttons.matching(identifier: "Increment").element(boundBy: 0).tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -39,6 +40,7 @@ final class iOS16_17_NewContainsOldTests: BaseIntegrationTests { } } + @MainActor func testObserveChildCount() { self.app.buttons["Toggle observe child count"].tap() XCTAssertEqual(self.app.staticTexts["Child count: 0"].exists, true) @@ -49,6 +51,7 @@ final class iOS16_17_NewContainsOldTests: BaseIntegrationTests { } } + @MainActor func testIncrementChild_ObservingChildCount() { self.app.buttons["Toggle observe child count"].tap() self.clearLogs() @@ -76,6 +79,7 @@ final class iOS16_17_NewContainsOldTests: BaseIntegrationTests { } } + @MainActor func testDeinit() { self.app.buttons["Toggle observe child count"].tap() self.app.buttons.matching(identifier: "Increment").element(boundBy: 1).tap() diff --git a/Examples/Integration/IntegrationUITests/iOS 16+17/NewOldSiblingsTests.swift b/Examples/Integration/IntegrationUITests/iOS 16+17/NewOldSiblingsTests.swift index cedf47c39f2e..bfdd90ecc291 100644 --- a/Examples/Integration/IntegrationUITests/iOS 16+17/NewOldSiblingsTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 16+17/NewOldSiblingsTests.swift @@ -2,16 +2,17 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS16_17_NewOldSiblingsTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 16 + 17"].tap() self.app.buttons["Siblings"].tap() self.clearLogs() - //SnapshotTesting.isRecording = true + // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons.matching(identifier: "Increment").element(boundBy: 0).tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -33,6 +34,7 @@ final class iOS16_17_NewOldSiblingsTests: BaseIntegrationTests { } } + @MainActor func testResetAll() { self.app.buttons.matching(identifier: "Increment").element(boundBy: 0).tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -54,6 +56,7 @@ final class iOS16_17_NewOldSiblingsTests: BaseIntegrationTests { } } + @MainActor func testResetSelf() { self.app.buttons.matching(identifier: "Increment").element(boundBy: 0).tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) diff --git a/Examples/Integration/IntegrationUITests/iOS 16+17/NewPresentsOldTests.swift b/Examples/Integration/IntegrationUITests/iOS 16+17/NewPresentsOldTests.swift index 75caf19fd96d..ade5f216c5dd 100644 --- a/Examples/Integration/IntegrationUITests/iOS 16+17/NewPresentsOldTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 16+17/NewPresentsOldTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS16_17_NewPresentsOldTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 16 + 17"].tap() @@ -12,6 +12,7 @@ final class iOS16_17_NewPresentsOldTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons["Increment"].tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -30,6 +31,7 @@ final class iOS16_17_NewPresentsOldTests: BaseIntegrationTests { } } + @MainActor func testPresentChild_NotObservingChildCount() { self.app.buttons["Present child"].tap() self.assertLogs { @@ -67,6 +69,7 @@ final class iOS16_17_NewPresentsOldTests: BaseIntegrationTests { } } + @MainActor func testDismissChild_NotObservingChildCount() { self.app.buttons["Present child"].tap() self.clearLogs() @@ -152,6 +155,7 @@ final class iOS16_17_NewPresentsOldTests: BaseIntegrationTests { } } + @MainActor func testObserveChildCount() { self.app.buttons["Toggle observe child count"].tap() XCTAssertEqual(self.app.staticTexts["Child count: N/A"].exists, true) @@ -170,6 +174,7 @@ final class iOS16_17_NewPresentsOldTests: BaseIntegrationTests { } } + @MainActor func testPresentChild_ObservingChildCount() { self.app.buttons["Toggle observe child count"].tap() self.clearLogs() @@ -211,6 +216,7 @@ final class iOS16_17_NewPresentsOldTests: BaseIntegrationTests { } } + @MainActor func testIncrementChild_ObservingChildCount() { self.app.buttons["Toggle observe child count"].tap() self.app.buttons["Present child"].tap() @@ -277,6 +283,7 @@ final class iOS16_17_NewPresentsOldTests: BaseIntegrationTests { } } + @MainActor func testDismissChild_ObservingChildCount() { self.app.buttons["Toggle observe child count"].tap() self.app.buttons["Present child"].tap() @@ -363,6 +370,7 @@ final class iOS16_17_NewPresentsOldTests: BaseIntegrationTests { } } + @MainActor func testDeinit() { self.app.buttons["Toggle observe child count"].tap() self.app.buttons["Present child"].tap() diff --git a/Examples/Integration/IntegrationUITests/iOS 16+17/OldContainsNewTests.swift b/Examples/Integration/IntegrationUITests/iOS 16+17/OldContainsNewTests.swift index 5bcfc5ece90b..c6f59983a211 100644 --- a/Examples/Integration/IntegrationUITests/iOS 16+17/OldContainsNewTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 16+17/OldContainsNewTests.swift @@ -2,16 +2,17 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS16_17_OldContainsNewTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 16 + 17"].tap() self.app.buttons["Old containing new"].tap() self.clearLogs() - //SnapshotTesting.isRecording = true + // SnapshotTesting.isRecording = true } + @MainActor func testIncrementDecrement() { self.app.buttons.matching(identifier: "Increment").element(boundBy: 0).tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -47,6 +48,7 @@ final class iOS16_17_OldContainsNewTests: BaseIntegrationTests { } } + @MainActor func testObserveChildCount() { self.app.buttons["Toggle observing child count"].tap() XCTAssertEqual(self.app.staticTexts["Child count: 0"].exists, true) @@ -60,6 +62,7 @@ final class iOS16_17_OldContainsNewTests: BaseIntegrationTests { } } + @MainActor func testIncrementChild_ObservingChildCount() { self.app.buttons["Toggle observing child count"].tap() self.clearLogs() @@ -87,6 +90,7 @@ final class iOS16_17_OldContainsNewTests: BaseIntegrationTests { } } + @MainActor func testDeinit() { self.app.buttons["Toggle observing child count"].tap() self.app.buttons.matching(identifier: "Increment").element(boundBy: 1).tap() diff --git a/Examples/Integration/IntegrationUITests/iOS 16+17/OldPresentsNewTests.swift b/Examples/Integration/IntegrationUITests/iOS 16+17/OldPresentsNewTests.swift index 35195d86db1f..bdf16bd29c09 100644 --- a/Examples/Integration/IntegrationUITests/iOS 16+17/OldPresentsNewTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 16+17/OldPresentsNewTests.swift @@ -2,16 +2,17 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS16_17_OldPresentsNewTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 16 + 17"].tap() self.app.buttons["Old presents new"].tap() self.clearLogs() - //SnapshotTesting.isRecording = true + // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons["Increment"].tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -26,6 +27,7 @@ final class iOS16_17_OldPresentsNewTests: BaseIntegrationTests { } // TODO: Flakey test + @MainActor func testPresentChild_NotObservingChildCount() { self.app.buttons["Present child"].tap() self.assertLogs { @@ -49,6 +51,7 @@ final class iOS16_17_OldPresentsNewTests: BaseIntegrationTests { } // TODO: Flakey test + @MainActor func testDismissChild_NotObservingChildCount() { self.app.buttons["Present child"].tap() self.clearLogs() @@ -63,6 +66,7 @@ final class iOS16_17_OldPresentsNewTests: BaseIntegrationTests { } } + @MainActor func testObserveChildCount() { self.app.buttons["Toggle observe child count"].tap() XCTAssertEqual(self.app.staticTexts["Child count: N/A"].exists, true) @@ -77,6 +81,7 @@ final class iOS16_17_OldPresentsNewTests: BaseIntegrationTests { } // TODO: Flakey test + @MainActor func testPresentChild_ObservingChildCount() { self.app.buttons["Toggle observe child count"].tap() self.clearLogs() @@ -101,6 +106,7 @@ final class iOS16_17_OldPresentsNewTests: BaseIntegrationTests { } } + @MainActor func testIncrementChild_ObservingChildCount() { self.app.buttons["Toggle observe child count"].tap() self.app.buttons["Present child"].tap() @@ -120,6 +126,7 @@ final class iOS16_17_OldPresentsNewTests: BaseIntegrationTests { } // TODO: Flakey test + @MainActor func testDismissChild_ObservingChildCount() { self.app.buttons["Toggle observe child count"].tap() self.app.buttons["Present child"].tap() @@ -141,6 +148,7 @@ final class iOS16_17_OldPresentsNewTests: BaseIntegrationTests { } } + @MainActor func testDeinit() { self.app.buttons["Toggle observe child count"].tap() self.app.buttons["Present child"].tap() diff --git a/Examples/Integration/IntegrationUITests/iOS 16/BasicsTests.swift b/Examples/Integration/IntegrationUITests/iOS 16/BasicsTests.swift index d42b584a121f..786ce817b0f8 100644 --- a/Examples/Integration/IntegrationUITests/iOS 16/BasicsTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 16/BasicsTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS16_BasicsTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try super.setUpWithError() self.app.buttons["iOS 16"].tap() @@ -12,6 +12,7 @@ final class iOS16_BasicsTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { XCTAssertEqual(self.app.staticTexts["0"].exists, true) XCTAssertEqual(self.app.staticTexts["1"].exists, false) diff --git a/Examples/Integration/IntegrationUITests/iOS 16/EnumTests.swift b/Examples/Integration/IntegrationUITests/iOS 16/EnumTests.swift index ee02f2530314..6e98d776cd3b 100644 --- a/Examples/Integration/IntegrationUITests/iOS 16/EnumTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 16/EnumTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS16_EnumTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try super.setUpWithError() self.app.buttons["iOS 16"].tap() @@ -12,6 +12,7 @@ final class iOS16_EnumTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons["Toggle feature 1 on"].tap() XCTAssertEqual(self.app.staticTexts["FEATURE 1"].exists, true) @@ -61,6 +62,7 @@ final class iOS16_EnumTests: BaseIntegrationTests { } } + @MainActor func testToggle1On_Toggle1Off() { self.app.buttons["Toggle feature 1 on"].tap() XCTAssertEqual(self.app.staticTexts["FEATURE 1"].exists, true) @@ -80,6 +82,7 @@ final class iOS16_EnumTests: BaseIntegrationTests { } } + @MainActor func testToggle1On_Toggle2On() { self.app.buttons["Toggle feature 1 on"].tap() XCTAssertEqual(self.app.staticTexts["FEATURE 1"].exists, true) @@ -126,6 +129,7 @@ final class iOS16_EnumTests: BaseIntegrationTests { } } + @MainActor func testToggle1On_Increment_Toggle1OffOn() { self.app.buttons["Toggle feature 1 on"].tap() XCTAssertEqual(self.app.staticTexts["FEATURE 1"].exists, true) @@ -154,6 +158,7 @@ final class iOS16_EnumTests: BaseIntegrationTests { } } + @MainActor func testDismiss() { self.app.buttons["Toggle feature 1 on"].tap() XCTAssertEqual(self.app.staticTexts["FEATURE 1"].exists, true) diff --git a/Examples/Integration/IntegrationUITests/iOS 16/IdentifiedListTests.swift b/Examples/Integration/IntegrationUITests/iOS 16/IdentifiedListTests.swift index d2b275c609c7..57b4f2ec7fa6 100644 --- a/Examples/Integration/IntegrationUITests/iOS 16/IdentifiedListTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 16/IdentifiedListTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS16_IdentifiedListTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try super.setUpWithError() self.app.buttons["iOS 16"].tap() @@ -12,6 +12,7 @@ final class iOS16_IdentifiedListTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons["Add"].tap() self.assertLogs { @@ -56,6 +57,7 @@ final class iOS16_IdentifiedListTests: BaseIntegrationTests { } } + @MainActor func testAddTwoIncrementFirst() { self.app.buttons["Add"].tap() self.app.buttons["Add"].tap() @@ -107,6 +109,7 @@ final class iOS16_IdentifiedListTests: BaseIntegrationTests { } } + @MainActor func testAddTwoIncrementSecond() { self.app.buttons["Add"].tap() self.app.buttons["Add"].tap() diff --git a/Examples/Integration/IntegrationUITests/iOS 16/NavigationTests.swift b/Examples/Integration/IntegrationUITests/iOS 16/NavigationTests.swift index b29beb16d26f..ddb562ddc380 100644 --- a/Examples/Integration/IntegrationUITests/iOS 16/NavigationTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 16/NavigationTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS16_NavigationTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try super.setUpWithError() self.app.buttons["iOS 16"].tap() @@ -12,6 +12,7 @@ final class iOS16_NavigationTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons["Push feature"].tap() self.assertLogs { @@ -37,6 +38,7 @@ final class iOS16_NavigationTests: BaseIntegrationTests { } } + @MainActor func testDeepStack() { self.app.buttons["Push feature"].tap() self.app.buttons["Push feature"].tap() diff --git a/Examples/Integration/IntegrationUITests/iOS 16/OptionalTests.swift b/Examples/Integration/IntegrationUITests/iOS 16/OptionalTests.swift index 3c9a4d9b91e3..3008d36437db 100644 --- a/Examples/Integration/IntegrationUITests/iOS 16/OptionalTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 16/OptionalTests.swift @@ -2,16 +2,17 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS16_OptionalTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 16"].tap() self.app.buttons["Optional"].tap() self.clearLogs() - //SnapshotTesting.isRecording = true + // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons["Toggle"].tap() self.assertLogs { @@ -44,6 +45,7 @@ final class iOS16_OptionalTests: BaseIntegrationTests { } } + @MainActor func testParentObserveChild() { self.app.buttons["Toggle"].tap() self.app.buttons["Increment"].tap() diff --git a/Examples/Integration/IntegrationUITests/iOS 16/PresentationTests.swift b/Examples/Integration/IntegrationUITests/iOS 16/PresentationTests.swift index a65800edd4de..016843c82516 100644 --- a/Examples/Integration/IntegrationUITests/iOS 16/PresentationTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 16/PresentationTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS16_PresentationTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try super.setUpWithError() self.app.buttons["iOS 16"].tap() @@ -12,6 +12,7 @@ final class iOS16_PresentationTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testOptional() throws { try XCTSkipIf(ProcessInfo.processInfo.environment["CI"] != nil) @@ -61,6 +62,7 @@ final class iOS16_PresentationTests: BaseIntegrationTests { } } + @MainActor func testOptional_ObserveChildCount() { self.app.buttons["Present sheet"].tap() self.assertLogs { diff --git a/Examples/Integration/IntegrationUITests/iOS 16/SiblingTests.swift b/Examples/Integration/IntegrationUITests/iOS 16/SiblingTests.swift index f7f6fb9f2b73..daf1cdd8fcb4 100644 --- a/Examples/Integration/IntegrationUITests/iOS 16/SiblingTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 16/SiblingTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS16_SiblingsTests: BaseIntegrationTests { + @MainActor override func setUpWithError() throws { try super.setUpWithError() self.app.buttons["iOS 16"].tap() @@ -12,6 +12,7 @@ final class iOS16_SiblingsTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons["Increment"].firstMatch.tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -25,6 +26,7 @@ final class iOS16_SiblingsTests: BaseIntegrationTests { } } + @MainActor func testResetAll() { self.app.buttons["Increment"].firstMatch.tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -45,6 +47,7 @@ final class iOS16_SiblingsTests: BaseIntegrationTests { } } + @MainActor func testResetSelf() { self.app.buttons["Increment"].firstMatch.tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -65,6 +68,7 @@ final class iOS16_SiblingsTests: BaseIntegrationTests { } } + @MainActor func testResetSwap() { self.app.buttons["Increment"].firstMatch.tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) diff --git a/Examples/Integration/IntegrationUITests/iOS 17/ObservableBasicsTests.swift b/Examples/Integration/IntegrationUITests/iOS 17/ObservableBasicsTests.swift index ae3657128570..ae6b75902591 100644 --- a/Examples/Integration/IntegrationUITests/iOS 17/ObservableBasicsTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 17/ObservableBasicsTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS17_ObservableBasicsTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 17"].tap() @@ -12,6 +12,7 @@ final class iOS17_ObservableBasicsTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { XCTAssertEqual(self.app.staticTexts["0"].exists, true) XCTAssertEqual(self.app.staticTexts["1"].exists, false) @@ -33,6 +34,7 @@ final class iOS17_ObservableBasicsTests: BaseIntegrationTests { } } + @MainActor func testReset() { self.app.buttons["Increment"].tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -55,6 +57,7 @@ final class iOS17_ObservableBasicsTests: BaseIntegrationTests { } } + @MainActor func testCopyIncrementDiscard() { self.app.buttons["Increment"].tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -77,6 +80,7 @@ final class iOS17_ObservableBasicsTests: BaseIntegrationTests { } } + @MainActor func testCopyIncrementSet() { self.app.buttons["Increment"].tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) diff --git a/Examples/Integration/IntegrationUITests/iOS 17/ObservableBindingLocalTests.swift b/Examples/Integration/IntegrationUITests/iOS 17/ObservableBindingLocalTests.swift index 02a3fa43858e..f98046bd9879 100644 --- a/Examples/Integration/IntegrationUITests/iOS 17/ObservableBindingLocalTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 17/ObservableBindingLocalTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS17_ObservableBindingLocalTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 17"].tap() @@ -12,6 +12,7 @@ final class iOS17_ObservableBindingLocalTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testNoBindingWarning_FullScreenCover() { self.app.buttons["Full-screen-cover"].tap() @@ -20,6 +21,7 @@ final class iOS17_ObservableBindingLocalTests: BaseIntegrationTests { self.app.buttons["Dismiss"].tap() } + @MainActor func testOnDisappearWarning_FullScreenCover() { self.expectRuntimeWarnings() @@ -32,6 +34,7 @@ final class iOS17_ObservableBindingLocalTests: BaseIntegrationTests { self.app.buttons["Dismiss"].tap() } + @MainActor func testNoBindingWarning_NavigationDestination() { self.app.buttons["Navigation destination"].tap() @@ -40,6 +43,7 @@ final class iOS17_ObservableBindingLocalTests: BaseIntegrationTests { self.app.buttons["Dismiss"].tap() } + @MainActor func testOnDisappearWarning_NavigationDestination() { self.expectRuntimeWarnings() @@ -52,6 +56,7 @@ final class iOS17_ObservableBindingLocalTests: BaseIntegrationTests { self.app.buttons["Dismiss"].tap() } + @MainActor func testNoBindingWarning_Path() { self.app.buttons["Path"].tap() @@ -60,6 +65,7 @@ final class iOS17_ObservableBindingLocalTests: BaseIntegrationTests { self.app.buttons["Dismiss"].tap() } + @MainActor func testOnDisappearWarning_Path() { self.expectRuntimeWarnings() @@ -72,6 +78,7 @@ final class iOS17_ObservableBindingLocalTests: BaseIntegrationTests { self.app.buttons["Dismiss"].tap() } + @MainActor func testNoBindingWarning_Popover() { self.app.buttons["Popover"].tap() @@ -80,6 +87,7 @@ final class iOS17_ObservableBindingLocalTests: BaseIntegrationTests { self.app.buttons["Dismiss"].tap() } + @MainActor func testOnDisappearWarning_Popover() { self.expectRuntimeWarnings() @@ -92,6 +100,7 @@ final class iOS17_ObservableBindingLocalTests: BaseIntegrationTests { self.app.buttons["Dismiss"].tap() } + @MainActor func testNoBindingWarning_Sheet() { self.app.buttons["Sheet"].tap() @@ -100,6 +109,7 @@ final class iOS17_ObservableBindingLocalTests: BaseIntegrationTests { self.app.buttons["Dismiss"].tap() } + @MainActor func testOnDisappearWarning_Sheet() { self.expectRuntimeWarnings() diff --git a/Examples/Integration/IntegrationUITests/iOS 17/ObservableEnumTests.swift b/Examples/Integration/IntegrationUITests/iOS 17/ObservableEnumTests.swift index 09308dcec5af..a2adfdcbe8db 100644 --- a/Examples/Integration/IntegrationUITests/iOS 17/ObservableEnumTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 17/ObservableEnumTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS17_ObservableEnumTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 17"].tap() @@ -12,6 +12,7 @@ final class iOS17_ObservableEnumTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons["Toggle feature 1 on"].tap() XCTAssertEqual(self.app.staticTexts["FEATURE 1"].exists, true) @@ -32,6 +33,7 @@ final class iOS17_ObservableEnumTests: BaseIntegrationTests { } } + @MainActor func testToggle1On_Toggle1Off() { self.app.buttons["Toggle feature 1 on"].tap() XCTAssertEqual(self.app.staticTexts["FEATURE 1"].exists, true) @@ -46,6 +48,7 @@ final class iOS17_ObservableEnumTests: BaseIntegrationTests { } } + @MainActor func testToggle1On_Toggle2On() { self.app.buttons["Toggle feature 1 on"].tap() XCTAssertEqual(self.app.staticTexts["FEATURE 1"].exists, true) @@ -62,6 +65,7 @@ final class iOS17_ObservableEnumTests: BaseIntegrationTests { } } + @MainActor func testDismiss() { self.app.buttons["Toggle feature 1 on"].tap() XCTAssertEqual(self.app.staticTexts["FEATURE 1"].exists, true) diff --git a/Examples/Integration/IntegrationUITests/iOS 17/ObservableIdentifiedListTests.swift b/Examples/Integration/IntegrationUITests/iOS 17/ObservableIdentifiedListTests.swift index 667a5deba2c5..cc00b74f92ab 100644 --- a/Examples/Integration/IntegrationUITests/iOS 17/ObservableIdentifiedListTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 17/ObservableIdentifiedListTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS17_ObservableIdentifiedListTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 17"].tap() @@ -12,6 +12,7 @@ final class iOS17_ObservableIdentifiedListTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons["Add"].tap() self.assertLogs { @@ -25,6 +26,7 @@ final class iOS17_ObservableIdentifiedListTests: BaseIntegrationTests { } } + @MainActor func testAddTwoIncrementFirst() { self.app.buttons["Add"].tap() self.app.buttons["Add"].tap() @@ -41,6 +43,7 @@ final class iOS17_ObservableIdentifiedListTests: BaseIntegrationTests { } } + @MainActor func testAddTwoIncrementSecond() { self.app.buttons["Add"].tap() self.app.buttons["Add"].tap() diff --git a/Examples/Integration/IntegrationUITests/iOS 17/ObservableNavigationTests.swift b/Examples/Integration/IntegrationUITests/iOS 17/ObservableNavigationTests.swift index eeda36db8f6b..4276459982cf 100644 --- a/Examples/Integration/IntegrationUITests/iOS 17/ObservableNavigationTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 17/ObservableNavigationTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS17_ObservableNavigationTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 17"].tap() @@ -12,6 +12,7 @@ final class iOS17_ObservableNavigationTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons["Push feature"].tap() self.assertLogs { @@ -28,6 +29,7 @@ final class iOS17_ObservableNavigationTests: BaseIntegrationTests { } } + @MainActor func testDeepStack() { self.app.buttons["Push feature"].tap() self.app.buttons["Push feature"].tap() diff --git a/Examples/Integration/IntegrationUITests/iOS 17/ObservableOptionalTests.swift b/Examples/Integration/IntegrationUITests/iOS 17/ObservableOptionalTests.swift index 63761ee0ed05..4f635c0b8de1 100644 --- a/Examples/Integration/IntegrationUITests/iOS 17/ObservableOptionalTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 17/ObservableOptionalTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS17_ObservableOptionalTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 17"].tap() @@ -12,6 +12,7 @@ final class iOS17_ObservableOptionalTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons["Toggle"].tap() XCTAssertEqual(self.app.staticTexts["0"].exists, true) @@ -33,6 +34,7 @@ final class iOS17_ObservableOptionalTests: BaseIntegrationTests { } } + @MainActor func testParentObserveChild() { self.app.buttons["Toggle"].tap() self.app.buttons["Increment"].tap() diff --git a/Examples/Integration/IntegrationUITests/iOS 17/ObservablePresentationTests.swift b/Examples/Integration/IntegrationUITests/iOS 17/ObservablePresentationTests.swift index 3101a4440634..07320450dc5d 100644 --- a/Examples/Integration/IntegrationUITests/iOS 17/ObservablePresentationTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 17/ObservablePresentationTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS17_ObservablePresentationTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 17"].tap() @@ -12,6 +12,7 @@ final class iOS17_ObservablePresentationTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testOptional() { self.app.buttons["Present sheet"].tap() self.assertLogs { @@ -36,6 +37,7 @@ final class iOS17_ObservablePresentationTests: BaseIntegrationTests { } } + @MainActor func testOptional_ObserveChildCount() { self.app.buttons["Present sheet"].tap() self.assertLogs { diff --git a/Examples/Integration/IntegrationUITests/iOS 17/ObservableSiblingTests.swift b/Examples/Integration/IntegrationUITests/iOS 17/ObservableSiblingTests.swift index c7d317a9f113..7165ba86bc31 100644 --- a/Examples/Integration/IntegrationUITests/iOS 17/ObservableSiblingTests.swift +++ b/Examples/Integration/IntegrationUITests/iOS 17/ObservableSiblingTests.swift @@ -2,8 +2,8 @@ import InlineSnapshotTesting import TestCases import XCTest -@MainActor final class iOS17_ObservableSiblingsTests: BaseIntegrationTests { + @MainActor override func setUp() { super.setUp() self.app.buttons["iOS 17"].tap() @@ -12,6 +12,7 @@ final class iOS17_ObservableSiblingsTests: BaseIntegrationTests { // SnapshotTesting.isRecording = true } + @MainActor func testBasics() { self.app.buttons["Increment"].firstMatch.tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -22,6 +23,7 @@ final class iOS17_ObservableSiblingsTests: BaseIntegrationTests { } } + @MainActor func testResetAll() { self.app.buttons["Increment"].firstMatch.tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -39,6 +41,7 @@ final class iOS17_ObservableSiblingsTests: BaseIntegrationTests { } } + @MainActor func testResetSelf() { self.app.buttons["Increment"].firstMatch.tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) @@ -53,6 +56,7 @@ final class iOS17_ObservableSiblingsTests: BaseIntegrationTests { } } + @MainActor func testResetSwap() { self.app.buttons["Increment"].firstMatch.tap() XCTAssertEqual(self.app.staticTexts["1"].exists, true) diff --git a/Examples/Search/SearchTests/SearchTests.swift b/Examples/Search/SearchTests/SearchTests.swift index 3c5c0548cce2..3d7f3e2bd07e 100644 --- a/Examples/Search/SearchTests/SearchTests.swift +++ b/Examples/Search/SearchTests/SearchTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import Search -@MainActor final class SearchTests: XCTestCase { + @MainActor func testSearchAndClearQuery() async { let store = TestStore(initialState: Search.State()) { Search() @@ -25,11 +25,15 @@ final class SearchTests: XCTestCase { } } + @MainActor func testSearchFailure() async { let store = TestStore(initialState: Search.State()) { Search() } withDependencies: { - $0.weatherClient.search = { @Sendable _ in throw SomethingWentWrong() } + $0.weatherClient.search = { @Sendable _ in + struct SomethingWentWrong: Error {} + throw SomethingWentWrong() + } } await store.send(.searchQueryChanged("S")) { @@ -39,6 +43,7 @@ final class SearchTests: XCTestCase { await store.receive(\.searchResponse.failure) } + @MainActor func testClearQueryCancelsInFlightSearchRequest() async { let store = TestStore(initialState: Search.State()) { Search() @@ -55,6 +60,7 @@ final class SearchTests: XCTestCase { } } + @MainActor func testTapOnLocation() async { let specialResult = GeocodingSearch.Result( country: "Special Country", @@ -107,6 +113,7 @@ final class SearchTests: XCTestCase { } } + @MainActor func testTapOnLocationCancelsInFlightRequest() async { let specialResult = GeocodingSearch.Result( country: "Special Country", @@ -168,13 +175,17 @@ final class SearchTests: XCTestCase { } } + @MainActor func testTapOnLocationFailure() async { let results = GeocodingSearch.mock.results let store = TestStore(initialState: Search.State(results: results)) { Search() } withDependencies: { - $0.weatherClient.forecast = { @Sendable _ in throw SomethingWentWrong() } + $0.weatherClient.forecast = { @Sendable _ in + struct SomethingWentWrong: Error {} + throw SomethingWentWrong() + } } await store.send(.searchResultTapped(results.first!)) { @@ -185,5 +196,3 @@ final class SearchTests: XCTestCase { } } } - -private struct SomethingWentWrong: Equatable, Error {} diff --git a/Examples/SpeechRecognition/SpeechRecognitionTests/SpeechRecognitionTests.swift b/Examples/SpeechRecognition/SpeechRecognitionTests/SpeechRecognitionTests.swift index a728a7076242..cf5f8d3fe758 100644 --- a/Examples/SpeechRecognition/SpeechRecognitionTests/SpeechRecognitionTests.swift +++ b/Examples/SpeechRecognition/SpeechRecognitionTests/SpeechRecognitionTests.swift @@ -3,10 +3,8 @@ import XCTest @testable import SpeechRecognition -@MainActor final class SpeechRecognitionTests: XCTestCase { - let recognitionTask = AsyncThrowingStream.makeStream(of: SpeechRecognitionResult.self) - + @MainActor func testDenyAuthorization() async { let store = TestStore(initialState: SpeechRecognition.State()) { SpeechRecognition() @@ -29,6 +27,7 @@ final class SpeechRecognitionTests: XCTestCase { } } + @MainActor func testRestrictedAuthorization() async { let store = TestStore(initialState: SpeechRecognition.State()) { SpeechRecognition() @@ -45,12 +44,14 @@ final class SpeechRecognitionTests: XCTestCase { } } + @MainActor func testAllowAndRecord() async { + let recognitionTask = AsyncThrowingStream.makeStream(of: SpeechRecognitionResult.self) let store = TestStore(initialState: SpeechRecognition.State()) { SpeechRecognition() } withDependencies: { - $0.speechClient.finishTask = { self.recognitionTask.continuation.finish() } - $0.speechClient.startTask = { @Sendable _ in self.recognitionTask.stream } + $0.speechClient.finishTask = { recognitionTask.continuation.finish() } + $0.speechClient.startTask = { @Sendable _ in recognitionTask.stream } $0.speechClient.requestAuthorization = { .authorized } } @@ -71,12 +72,12 @@ final class SpeechRecognitionTests: XCTestCase { await store.receive(\.speechRecognizerAuthorizationStatusResponse) - self.recognitionTask.continuation.yield(firstResult) + recognitionTask.continuation.yield(firstResult) await store.receive(\.speech.success) { $0.transcribedText = "Hello" } - self.recognitionTask.continuation.yield(secondResult) + recognitionTask.continuation.yield(secondResult) await store.receive(\.speech.success) { $0.transcribedText = "Hello world" } @@ -88,11 +89,13 @@ final class SpeechRecognitionTests: XCTestCase { await store.finish() } + @MainActor func testAudioSessionFailure() async { + let recognitionTask = AsyncThrowingStream.makeStream(of: SpeechRecognitionResult.self) let store = TestStore(initialState: SpeechRecognition.State()) { SpeechRecognition() } withDependencies: { - $0.speechClient.startTask = { @Sendable _ in self.recognitionTask.stream } + $0.speechClient.startTask = { @Sendable _ in recognitionTask.stream } $0.speechClient.requestAuthorization = { .authorized } } @@ -108,11 +111,13 @@ final class SpeechRecognitionTests: XCTestCase { } } + @MainActor func testAudioEngineFailure() async { + let recognitionTask = AsyncThrowingStream.makeStream(of: SpeechRecognitionResult.self) let store = TestStore(initialState: SpeechRecognition.State()) { SpeechRecognition() } withDependencies: { - $0.speechClient.startTask = { @Sendable _ in self.recognitionTask.stream } + $0.speechClient.startTask = { @Sendable _ in recognitionTask.stream } $0.speechClient.requestAuthorization = { .authorized } } diff --git a/Examples/SyncUps/SyncUpsTests/AppFeatureTests.swift b/Examples/SyncUps/SyncUpsTests/AppFeatureTests.swift index c3e1b296b797..cf07cfbd0f35 100644 --- a/Examples/SyncUps/SyncUpsTests/AppFeatureTests.swift +++ b/Examples/SyncUps/SyncUpsTests/AppFeatureTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SyncUps -@MainActor final class AppFeatureTests: XCTestCase { + @MainActor func testDelete() async throws { let syncUp = SyncUp.mock @@ -37,6 +37,7 @@ final class AppFeatureTests: XCTestCase { } } + @MainActor func testDetailEdit() async throws { var syncUp = SyncUp.mock let savedData = LockIsolated(Data?.none) @@ -86,6 +87,7 @@ final class AppFeatureTests: XCTestCase { ) } + @MainActor func testRecording() async { let speechResult = SpeechRecognitionResult( bestTranscription: Transcription(formattedString: "I completed the project"), diff --git a/Examples/SyncUps/SyncUpsTests/RecordMeetingTests.swift b/Examples/SyncUps/SyncUpsTests/RecordMeetingTests.swift index 2b2e5d23441c..2b63f42266c4 100644 --- a/Examples/SyncUps/SyncUpsTests/RecordMeetingTests.swift +++ b/Examples/SyncUps/SyncUpsTests/RecordMeetingTests.swift @@ -3,9 +3,9 @@ import XCTest @testable import SyncUps -@MainActor final class RecordMeetingTests: XCTestCase { - func testTimer() async throws { + @MainActor + func testTimer() async { let clock = TestClock() let dismissed = self.expectation(description: "dismissed") @@ -76,11 +76,15 @@ final class RecordMeetingTests: XCTestCase { // NB: this improves on the onMeetingFinished pattern from vanilla SwiftUI await store.receive(\.delegate.save) + #if swift(>=5.10) + nonisolated(unsafe) let `self` = self + #endif await self.fulfillment(of: [dismissed]) await onTask.cancel() } - func testRecordTranscript() async throws { + @MainActor + func testRecordTranscript() async { let clock = TestClock() let dismissed = self.expectation(description: "dismissed") @@ -133,11 +137,15 @@ final class RecordMeetingTests: XCTestCase { await store.receive(\.delegate.save) + #if swift(>=5.10) + nonisolated(unsafe) let `self` = self + #endif await self.fulfillment(of: [dismissed]) await onTask.cancel() } - func testEndMeetingSave() async throws { + @MainActor + func testEndMeetingSave() async { let clock = TestClock() let dismissed = self.expectation(description: "dismissed") @@ -166,11 +174,15 @@ final class RecordMeetingTests: XCTestCase { await store.receive(\.delegate.save) + #if swift(>=5.10) + nonisolated(unsafe) let `self` = self + #endif await self.fulfillment(of: [dismissed]) await onTask.cancel() } - func testEndMeetingDiscard() async throws { + @MainActor + func testEndMeetingDiscard() async { let clock = TestClock() let dismissed = self.expectation(description: "dismissed") @@ -192,11 +204,15 @@ final class RecordMeetingTests: XCTestCase { $0.alert = nil } + #if swift(>=5.10) + nonisolated(unsafe) let `self` = self + #endif await self.fulfillment(of: [dismissed]) await task.cancel() } - func testNextSpeaker() async throws { + @MainActor + func testNextSpeaker() async { let clock = TestClock() let dismissed = self.expectation(description: "dismissed") @@ -241,11 +257,15 @@ final class RecordMeetingTests: XCTestCase { } await store.receive(\.delegate.save) + #if swift(>=5.10) + nonisolated(unsafe) let `self` = self + #endif await self.fulfillment(of: [dismissed]) await onTask.cancel() } - func testSpeechRecognitionFailure_Continue() async throws { + @MainActor + func testSpeechRecognitionFailure_Continue() async { let clock = TestClock() let dismissed = self.expectation(description: "dismissed") @@ -308,11 +328,15 @@ final class RecordMeetingTests: XCTestCase { store.exhaustivity = .on await store.receive(\.delegate.save) + #if swift(>=5.10) + nonisolated(unsafe) let `self` = self + #endif await self.fulfillment(of: [dismissed]) await onTask.cancel() } - func testSpeechRecognitionFailure_Discard() async throws { + @MainActor + func testSpeechRecognitionFailure_Discard() async { let clock = TestClock() let dismissed = self.expectation(description: "dismissed") @@ -340,6 +364,9 @@ final class RecordMeetingTests: XCTestCase { $0.alert = nil } + #if swift(>=5.10) + nonisolated(unsafe) let `self` = self + #endif await self.fulfillment(of: [dismissed]) await onTask.cancel() } diff --git a/Examples/SyncUps/SyncUpsTests/SyncUpDetailTests.swift b/Examples/SyncUps/SyncUpsTests/SyncUpDetailTests.swift index e4c121274ff1..a237d0269d50 100644 --- a/Examples/SyncUps/SyncUpsTests/SyncUpDetailTests.swift +++ b/Examples/SyncUps/SyncUpsTests/SyncUpDetailTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SyncUps -@MainActor final class SyncUpDetailTests: XCTestCase { + @MainActor func testSpeechRestricted() async { let store = TestStore(initialState: SyncUpDetail.State(syncUp: .mock)) { SyncUpDetail() @@ -17,6 +17,7 @@ final class SyncUpDetailTests: XCTestCase { } } + @MainActor func testSpeechDenied() async throws { let store = TestStore(initialState: SyncUpDetail.State(syncUp: .mock)) { SyncUpDetail() @@ -31,6 +32,7 @@ final class SyncUpDetailTests: XCTestCase { } } + @MainActor func testOpenSettings() async { let settingsOpened = LockIsolated(false) @@ -52,6 +54,7 @@ final class SyncUpDetailTests: XCTestCase { XCTAssertEqual(settingsOpened.value, true) } + @MainActor func testContinueWithoutRecording() async throws { let store = TestStore( initialState: SyncUpDetail.State( @@ -71,6 +74,7 @@ final class SyncUpDetailTests: XCTestCase { await store.receive(\.delegate.startMeeting) } + @MainActor func testSpeechAuthorized() async throws { let store = TestStore(initialState: SyncUpDetail.State(syncUp: .mock)) { SyncUpDetail() @@ -83,6 +87,7 @@ final class SyncUpDetailTests: XCTestCase { await store.receive(\.delegate.startMeeting) } + @MainActor func testEdit() async { var syncUp = SyncUp.mock let store = TestStore(initialState: SyncUpDetail.State(syncUp: syncUp)) { @@ -108,6 +113,7 @@ final class SyncUpDetailTests: XCTestCase { await store.receive(\.delegate.syncUpUpdated) } + @MainActor func testDelete() async { let didDismiss = LockIsolated(false) defer { XCTAssertEqual(didDismiss.value, true) } diff --git a/Examples/SyncUps/SyncUpsTests/SyncUpFormTests.swift b/Examples/SyncUps/SyncUpsTests/SyncUpFormTests.swift index 4e2e395d9d0d..66dc78759832 100644 --- a/Examples/SyncUps/SyncUpsTests/SyncUpFormTests.swift +++ b/Examples/SyncUps/SyncUpsTests/SyncUpFormTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SyncUps -@MainActor final class SyncUpFormTests: XCTestCase { + @MainActor func testAddAttendee() async { let store = TestStore( initialState: SyncUpForm.State( @@ -36,6 +36,7 @@ final class SyncUpFormTests: XCTestCase { } } + @MainActor func testFocus_RemoveAttendee() async { let store = TestStore( initialState: SyncUpForm.State( diff --git a/Examples/SyncUps/SyncUpsTests/SyncUpsListTests.swift b/Examples/SyncUps/SyncUpsTests/SyncUpsListTests.swift index 9f781de86caf..1cdf676a5985 100644 --- a/Examples/SyncUps/SyncUpsTests/SyncUpsListTests.swift +++ b/Examples/SyncUps/SyncUpsTests/SyncUpsListTests.swift @@ -3,8 +3,8 @@ import XCTest @testable import SyncUps -@MainActor final class SyncUpsListTests: XCTestCase { + @MainActor func testAdd() async throws { let store = TestStore(initialState: SyncUpsList.State()) { SyncUpsList() @@ -35,6 +35,7 @@ final class SyncUpsListTests: XCTestCase { } } + @MainActor func testAdd_ValidatedAttendees() async throws { @Dependency(\.uuid) var uuid @@ -75,6 +76,7 @@ final class SyncUpsListTests: XCTestCase { } } + @MainActor func testLoadingDataDecodingFailed() async throws { let store = TestStore(initialState: SyncUpsList.State()) { SyncUpsList() @@ -97,6 +99,7 @@ final class SyncUpsListTests: XCTestCase { } } + @MainActor func testLoadingDataFileNotFound() async throws { let store = TestStore(initialState: SyncUpsList.State()) { SyncUpsList() diff --git a/Examples/SyncUps/SyncUpsUITests/SyncUpsUITests.swift b/Examples/SyncUps/SyncUpsUITests/SyncUpsUITests.swift index 7ba2161e14da..072b5dd99b03 100644 --- a/Examples/SyncUps/SyncUpsUITests/SyncUpsUITests.swift +++ b/Examples/SyncUps/SyncUpsUITests/SyncUpsUITests.swift @@ -1,11 +1,13 @@ import XCTest final class SyncUpsUITests: XCTestCase { + @MainActor var app: XCUIApplication! + @MainActor override func setUpWithError() throws { - self.continueAfterFailure = false - self.app = XCUIApplication() + continueAfterFailure = false + app = XCUIApplication() app.launchEnvironment = [ "UITesting": "true" ] @@ -20,6 +22,7 @@ final class SyncUpsUITests: XCTestCase { // it takes 0.025 seconds (400 times faster) and it even tests more. It further confirms that when // the sync-up is added to the list its data will be persisted to disk so that it will be // available on next launch. + @MainActor func testAdd() throws { app.launch() app.navigationBars["Daily Sync-ups"].buttons["Add"].tap() diff --git a/Examples/TicTacToe/tic-tac-toe/Tests/AppCoreTests/AppCoreTests.swift b/Examples/TicTacToe/tic-tac-toe/Tests/AppCoreTests/AppCoreTests.swift index 825cdaab66bd..3b233271c75f 100644 --- a/Examples/TicTacToe/tic-tac-toe/Tests/AppCoreTests/AppCoreTests.swift +++ b/Examples/TicTacToe/tic-tac-toe/Tests/AppCoreTests/AppCoreTests.swift @@ -6,8 +6,8 @@ import NewGameCore import TwoFactorCore import XCTest -@MainActor final class AppCoreTests: XCTestCase { + @MainActor func testIntegration() async { let store = TestStore(initialState: TicTacToe.State.login(Login.State())) { TicTacToe.body @@ -38,6 +38,7 @@ final class AppCoreTests: XCTestCase { } } + @MainActor func testIntegration_TwoFactor() async { let store = TestStore(initialState: TicTacToe.State.login(Login.State())) { TicTacToe.body diff --git a/Examples/TicTacToe/tic-tac-toe/Tests/GameCoreTests/GameCoreTests.swift b/Examples/TicTacToe/tic-tac-toe/Tests/GameCoreTests/GameCoreTests.swift index 3ff50bf22508..aebc359d24d7 100644 --- a/Examples/TicTacToe/tic-tac-toe/Tests/GameCoreTests/GameCoreTests.swift +++ b/Examples/TicTacToe/tic-tac-toe/Tests/GameCoreTests/GameCoreTests.swift @@ -2,77 +2,81 @@ import ComposableArchitecture import GameCore import XCTest -@MainActor final class GameCoreTests: XCTestCase { - let store = TestStore( - initialState: Game.State( - oPlayerName: "Blob Jr.", - xPlayerName: "Blob Sr." - ) - ) { - Game() - } - + @MainActor func testFlow_Winner_Quit() async { - await self.store.send(.cellTapped(row: 0, column: 0)) { + let store = TestStore( + initialState: Game.State(oPlayerName: "Blob Jr.", xPlayerName: "Blob Sr.") + ) { + Game() + } + + await store.send(.cellTapped(row: 0, column: 0)) { $0.board[0][0] = .x $0.currentPlayer = .o } - await self.store.send(.cellTapped(row: 2, column: 1)) { + await store.send(.cellTapped(row: 2, column: 1)) { $0.board[2][1] = .o $0.currentPlayer = .x } - await self.store.send(.cellTapped(row: 1, column: 0)) { + await store.send(.cellTapped(row: 1, column: 0)) { $0.board[1][0] = .x $0.currentPlayer = .o } - await self.store.send(.cellTapped(row: 1, column: 1)) { + await store.send(.cellTapped(row: 1, column: 1)) { $0.board[1][1] = .o $0.currentPlayer = .x } - await self.store.send(.cellTapped(row: 2, column: 0)) { + await store.send(.cellTapped(row: 2, column: 0)) { $0.board[2][0] = .x } } + @MainActor func testFlow_Tie() async { - await self.store.send(.cellTapped(row: 0, column: 0)) { + let store = TestStore( + initialState: Game.State(oPlayerName: "Blob Jr.", xPlayerName: "Blob Sr.") + ) { + Game() + } + + await store.send(.cellTapped(row: 0, column: 0)) { $0.board[0][0] = .x $0.currentPlayer = .o } - await self.store.send(.cellTapped(row: 2, column: 2)) { + await store.send(.cellTapped(row: 2, column: 2)) { $0.board[2][2] = .o $0.currentPlayer = .x } - await self.store.send(.cellTapped(row: 1, column: 0)) { + await store.send(.cellTapped(row: 1, column: 0)) { $0.board[1][0] = .x $0.currentPlayer = .o } - await self.store.send(.cellTapped(row: 2, column: 0)) { + await store.send(.cellTapped(row: 2, column: 0)) { $0.board[2][0] = .o $0.currentPlayer = .x } - await self.store.send(.cellTapped(row: 2, column: 1)) { + await store.send(.cellTapped(row: 2, column: 1)) { $0.board[2][1] = .x $0.currentPlayer = .o } - await self.store.send(.cellTapped(row: 1, column: 2)) { + await store.send(.cellTapped(row: 1, column: 2)) { $0.board[1][2] = .o $0.currentPlayer = .x } - await self.store.send(.cellTapped(row: 0, column: 2)) { + await store.send(.cellTapped(row: 0, column: 2)) { $0.board[0][2] = .x $0.currentPlayer = .o } - await self.store.send(.cellTapped(row: 0, column: 1)) { + await store.send(.cellTapped(row: 0, column: 1)) { $0.board[0][1] = .o $0.currentPlayer = .x } - await self.store.send(.cellTapped(row: 1, column: 1)) { + await store.send(.cellTapped(row: 1, column: 1)) { $0.board[1][1] = .x $0.currentPlayer = .o } - await self.store.send(.playAgainButtonTapped) { + await store.send(.playAgainButtonTapped) { $0 = Game.State(oPlayerName: "Blob Jr.", xPlayerName: "Blob Sr.") } } diff --git a/Examples/TicTacToe/tic-tac-toe/Tests/LoginCoreTests/LoginCoreTests.swift b/Examples/TicTacToe/tic-tac-toe/Tests/LoginCoreTests/LoginCoreTests.swift index 84d4837a44c7..3487c7d4288d 100644 --- a/Examples/TicTacToe/tic-tac-toe/Tests/LoginCoreTests/LoginCoreTests.swift +++ b/Examples/TicTacToe/tic-tac-toe/Tests/LoginCoreTests/LoginCoreTests.swift @@ -4,8 +4,8 @@ import LoginCore import TwoFactorCore import XCTest -@MainActor final class LoginCoreTests: XCTestCase { + @MainActor func testFlow_Success_TwoFactor_Integration() async { let store = TestStore(initialState: Login.State()) { Login() @@ -45,6 +45,7 @@ final class LoginCoreTests: XCTestCase { await twoFactorPresentationTask.cancel() } + @MainActor func testFlow_DismissEarly_TwoFactor_Integration() async { let store = TestStore(initialState: Login.State()) { Login() diff --git a/Examples/TicTacToe/tic-tac-toe/Tests/NewGameCoreTests/NewGameCoreTests.swift b/Examples/TicTacToe/tic-tac-toe/Tests/NewGameCoreTests/NewGameCoreTests.swift index 59839672426e..f8eb4bf1088d 100644 --- a/Examples/TicTacToe/tic-tac-toe/Tests/NewGameCoreTests/NewGameCoreTests.swift +++ b/Examples/TicTacToe/tic-tac-toe/Tests/NewGameCoreTests/NewGameCoreTests.swift @@ -3,36 +3,35 @@ import GameCore import NewGameCore import XCTest -@MainActor final class NewGameCoreTests: XCTestCase { - let store = TestStore(initialState: NewGame.State()) { - NewGame() - } - + @MainActor func testFlow_NewGame_Integration() async { - await self.store.send(\.binding.oPlayerName, "Blob Sr.") { + let store = TestStore(initialState: NewGame.State()) { + NewGame() + } + await store.send(\.binding.oPlayerName, "Blob Sr.") { $0.oPlayerName = "Blob Sr." } - await self.store.send(\.binding.xPlayerName, "Blob Jr.") { + await store.send(\.binding.xPlayerName, "Blob Jr.") { $0.xPlayerName = "Blob Jr." } - await self.store.send(.letsPlayButtonTapped) { + await store.send(.letsPlayButtonTapped) { $0.game = Game.State(oPlayerName: "Blob Sr.", xPlayerName: "Blob Jr.") } - await self.store.send(\.game.cellTapped, (row: 0, column: 0)) { + await store.send(\.game.cellTapped, (row: 0, column: 0)) { $0.game!.board[0][0] = .x $0.game!.currentPlayer = .o } - await self.store.send(\.game.quitButtonTapped) - await self.store.receive(\.game.dismiss) { + await store.send(\.game.quitButtonTapped) + await store.receive(\.game.dismiss) { $0.game = nil } - await self.store.send(.letsPlayButtonTapped) { + await store.send(.letsPlayButtonTapped) { $0.game = Game.State(oPlayerName: "Blob Sr.", xPlayerName: "Blob Jr.") } - await self.store.send(\.game.dismiss) { + await store.send(\.game.dismiss) { $0.game = nil } - await self.store.send(.logoutButtonTapped) + await store.send(.logoutButtonTapped) } } diff --git a/Examples/TicTacToe/tic-tac-toe/Tests/TwoFactorCoreTests/TwoFactorCoreTests.swift b/Examples/TicTacToe/tic-tac-toe/Tests/TwoFactorCoreTests/TwoFactorCoreTests.swift index 340dc26096c6..cf83b514cd56 100644 --- a/Examples/TicTacToe/tic-tac-toe/Tests/TwoFactorCoreTests/TwoFactorCoreTests.swift +++ b/Examples/TicTacToe/tic-tac-toe/Tests/TwoFactorCoreTests/TwoFactorCoreTests.swift @@ -3,8 +3,8 @@ import ComposableArchitecture import TwoFactorCore import XCTest -@MainActor final class TwoFactorCoreTests: XCTestCase { + @MainActor func testFlow_Success() async { let store = TestStore(initialState: TwoFactor.State(token: "deadbeefdeadbeef")) { TwoFactor() @@ -35,6 +35,7 @@ final class TwoFactorCoreTests: XCTestCase { } } + @MainActor func testFlow_Failure() async { let store = TestStore(initialState: TwoFactor.State(token: "deadbeefdeadbeef")) { TwoFactor() diff --git a/Examples/Todos/Todos/Todos.swift b/Examples/Todos/Todos/Todos.swift index 0b7d29fddc9e..bfb26cf35575 100644 --- a/Examples/Todos/Todos/Todos.swift +++ b/Examples/Todos/Todos/Todos.swift @@ -1,5 +1,5 @@ import ComposableArchitecture -@preconcurrency import SwiftUI +import SwiftUI enum Filter: LocalizedStringKey, CaseIterable, Hashable { case all = "All" diff --git a/Examples/Todos/TodosTests/TodosTests.swift b/Examples/Todos/TodosTests/TodosTests.swift index 28c4b9847828..3265cc9fdbc8 100644 --- a/Examples/Todos/TodosTests/TodosTests.swift +++ b/Examples/Todos/TodosTests/TodosTests.swift @@ -3,10 +3,10 @@ import XCTest @testable import Todos -@MainActor final class TodosTests: XCTestCase { let clock = TestClock() + @MainActor func testAddTodo() async { let store = TestStore(initialState: Todos.State()) { Todos() @@ -41,6 +41,7 @@ final class TodosTests: XCTestCase { } } + @MainActor func testEditTodo() async { let state = Todos.State( todos: [ @@ -61,6 +62,7 @@ final class TodosTests: XCTestCase { } } + @MainActor func testCompleteTodo() async { let state = Todos.State( todos: [ @@ -95,6 +97,7 @@ final class TodosTests: XCTestCase { } } + @MainActor func testCompleteTodoDebounces() async { let state = Todos.State( todos: [ @@ -128,6 +131,7 @@ final class TodosTests: XCTestCase { await store.receive(\.sortCompletedTodos) } + @MainActor func testClearCompleted() async { let state = Todos.State( todos: [ @@ -155,6 +159,7 @@ final class TodosTests: XCTestCase { } } + @MainActor func testDelete() async { let state = Todos.State( todos: [ @@ -188,6 +193,7 @@ final class TodosTests: XCTestCase { } } + @MainActor func testDeleteWhileFiltered() async { let state = Todos.State( filter: .completed, @@ -222,6 +228,7 @@ final class TodosTests: XCTestCase { } } + @MainActor func testEditModeMoving() async { let state = Todos.State( todos: [ @@ -263,6 +270,7 @@ final class TodosTests: XCTestCase { await store.receive(\.sortCompletedTodos) } + @MainActor func testEditModeMovingWithFilter() async { let state = Todos.State( todos: [ @@ -314,6 +322,7 @@ final class TodosTests: XCTestCase { await store.receive(\.sortCompletedTodos) } + @MainActor func testFilteredEdit() async { let state = Todos.State( todos: [ diff --git a/Examples/VoiceMemos/VoiceMemosTests/VoiceMemosTests.swift b/Examples/VoiceMemos/VoiceMemosTests/VoiceMemosTests.swift index 8473542dd622..dc69d8603be8 100644 --- a/Examples/VoiceMemos/VoiceMemosTests/VoiceMemosTests.swift +++ b/Examples/VoiceMemos/VoiceMemosTests/VoiceMemosTests.swift @@ -6,17 +6,16 @@ import XCTest let deadbeefID = UUID(uuidString: "DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF")! let deadbeefURL = URL(fileURLWithPath: "/tmp/DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF.m4a") -@MainActor final class VoiceMemosTests: XCTestCase { - let clock = TestClock() - + @MainActor func testRecordAndPlayback() async throws { let didFinish = AsyncThrowingStream.makeStream(of: Bool.self) + let clock = TestClock() let store = TestStore(initialState: VoiceMemos.State()) { VoiceMemos() } withDependencies: { $0.audioPlayer.play = { @Sendable _ in - try await self.clock.sleep(for: .milliseconds(2_500)) + try await clock.sleep(for: .milliseconds(2_500)) return true } $0.audioRecorder.currentTime = { 2.5 } @@ -29,7 +28,7 @@ final class VoiceMemosTests: XCTestCase { didFinish.continuation.finish() } $0.date = .constant(Date(timeIntervalSinceReferenceDate: 0)) - $0.continuousClock = self.clock + $0.continuousClock = clock $0.temporaryDirectory = { URL(fileURLWithPath: "/tmp") } $0.uuid = .constant(deadbeefID) } @@ -67,7 +66,7 @@ final class VoiceMemosTests: XCTestCase { $0.voiceMemos[id: deadbeefURL]?.mode = .playing(progress: 0) } await store.receive(\.voiceMemos[id:deadbeefURL].delegate.playbackStarted) - await self.clock.run() + await clock.run() await store.receive(\.voiceMemos[id:deadbeefURL].timerUpdated) { $0.voiceMemos[id: deadbeefURL]?.mode = .playing(progress: 0.2) @@ -86,9 +85,10 @@ final class VoiceMemosTests: XCTestCase { } } + @MainActor func testRecordMemoHappyPath() async throws { let didFinish = AsyncThrowingStream.makeStream(of: Bool.self) - + let clock = TestClock() let store = TestStore(initialState: VoiceMemos.State()) { VoiceMemos() } withDependencies: { @@ -102,13 +102,13 @@ final class VoiceMemosTests: XCTestCase { didFinish.continuation.finish() } $0.date = .constant(Date(timeIntervalSinceReferenceDate: 0)) - $0.continuousClock = self.clock + $0.continuousClock = clock $0.temporaryDirectory = { URL(fileURLWithPath: "/tmp") } $0.uuid = .constant(UUID(uuidString: "DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF")!) } await store.send(.recordButtonTapped) - await self.clock.advance() + await clock.advance() await store.receive(\.recordPermissionResponse) { $0.audioRecorderPermission = .allowed $0.recordingMemo = RecordingMemo.State( @@ -118,15 +118,15 @@ final class VoiceMemosTests: XCTestCase { ) } let recordingMemoTask = await store.send(\.recordingMemo.onTask) - await self.clock.advance(by: .seconds(1)) + await clock.advance(by: .seconds(1)) await store.receive(\.recordingMemo.timerUpdated) { $0.recordingMemo?.duration = 1 } - await self.clock.advance(by: .seconds(1)) + await clock.advance(by: .seconds(1)) await store.receive(\.recordingMemo.timerUpdated) { $0.recordingMemo?.duration = 2 } - await self.clock.advance(by: .milliseconds(500)) + await clock.advance(by: .milliseconds(500)) await store.send(\.recordingMemo.stopButtonTapped) { $0.recordingMemo?.mode = .encoding } @@ -149,6 +149,7 @@ final class VoiceMemosTests: XCTestCase { await recordingMemoTask.cancel() } + @MainActor func testPermissionDenied() async { var didOpenSettings = false let store = TestStore(initialState: VoiceMemos.State()) { @@ -170,10 +171,11 @@ final class VoiceMemosTests: XCTestCase { XCTAssert(didOpenSettings) } + @MainActor func testRecordMemoFailure() async { struct SomeError: Error, Equatable {} let didFinish = AsyncThrowingStream.makeStream(of: Bool.self) - + let clock = TestClock() let store = TestStore(initialState: VoiceMemos.State()) { VoiceMemos() } withDependencies: { @@ -181,7 +183,7 @@ final class VoiceMemosTests: XCTestCase { $0.audioRecorder.startRecording = { @Sendable _ in try await didFinish.stream.first { _ in true }! } - $0.continuousClock = self.clock + $0.continuousClock = clock $0.date = .constant(Date(timeIntervalSinceReferenceDate: 0)) $0.temporaryDirectory = { URL(fileURLWithPath: "/tmp") } $0.uuid = .constant(deadbeefID) @@ -208,10 +210,11 @@ final class VoiceMemosTests: XCTestCase { // Demonstration of how to write a non-exhaustive test for recording a memo and it failing to // record. + @MainActor func testRecordMemoFailure_NonExhaustive() async { struct SomeError: Error, Equatable {} let didFinish = AsyncThrowingStream.makeStream(of: Bool.self) - + let clock = TestClock() let store = TestStore(initialState: VoiceMemos.State()) { VoiceMemos() } withDependencies: { @@ -220,7 +223,7 @@ final class VoiceMemosTests: XCTestCase { $0.audioRecorder.startRecording = { @Sendable _ in try await didFinish.stream.first { _ in true }! } - $0.continuousClock = self.clock + $0.continuousClock = clock $0.date = .constant(Date(timeIntervalSinceReferenceDate: 0)) $0.temporaryDirectory = { URL(fileURLWithPath: "/tmp") } $0.uuid = .constant(deadbeefID) @@ -236,8 +239,10 @@ final class VoiceMemosTests: XCTestCase { } } + @MainActor func testPlayMemoHappyPath() async { let url = URL(fileURLWithPath: "pointfreeco/functions.m4a") + let clock = TestClock() let store = TestStore( initialState: VoiceMemos.State( voiceMemos: [ @@ -254,34 +259,36 @@ final class VoiceMemosTests: XCTestCase { VoiceMemos() } withDependencies: { $0.audioPlayer.play = { @Sendable _ in - try await self.clock.sleep(for: .milliseconds(1_250)) + try await clock.sleep(for: .milliseconds(1_250)) return true } - $0.continuousClock = self.clock + $0.continuousClock = clock } await store.send(\.voiceMemos[id:url].playButtonTapped) { $0.voiceMemos[id: url]?.mode = .playing(progress: 0) } await store.receive(\.voiceMemos[id:url].delegate.playbackStarted) - await self.clock.advance(by: .milliseconds(500)) + await clock.advance(by: .milliseconds(500)) await store.receive(\.voiceMemos[id:url].timerUpdated) { $0.voiceMemos[id: url]?.mode = .playing(progress: 0.4) } - await self.clock.advance(by: .milliseconds(500)) + await clock.advance(by: .milliseconds(500)) await store.receive(\.voiceMemos[id:url].timerUpdated) { $0.voiceMemos[id: url]?.mode = .playing(progress: 0.8) } - await self.clock.advance(by: .milliseconds(250)) + await clock.advance(by: .milliseconds(250)) await store.receive(\.voiceMemos[id:url].audioPlayerClient.success) { $0.voiceMemos[id: url]?.mode = .notPlaying } } + @MainActor func testPlayMemoFailure() async { struct SomeError: Error, Equatable {} let url = URL(fileURLWithPath: "pointfreeco/functions.m4a") + let clock = TestClock() let store = TestStore( initialState: VoiceMemos.State( voiceMemos: [ @@ -298,7 +305,7 @@ final class VoiceMemosTests: XCTestCase { VoiceMemos() } withDependencies: { $0.audioPlayer.play = { @Sendable _ in throw SomeError() } - $0.continuousClock = self.clock + $0.continuousClock = clock } let task = await store.send(\.voiceMemos[id:url].playButtonTapped) { @@ -314,6 +321,7 @@ final class VoiceMemosTests: XCTestCase { await task.cancel() } + @MainActor func testStopMemo() async { let url = URL(fileURLWithPath: "pointfreeco/functions.m4a") let store = TestStore( @@ -337,6 +345,7 @@ final class VoiceMemosTests: XCTestCase { } } + @MainActor func testDeleteMemo() async { let url = URL(fileURLWithPath: "pointfreeco/functions.m4a") let store = TestStore( @@ -360,6 +369,7 @@ final class VoiceMemosTests: XCTestCase { } } + @MainActor func testDeleteMemos() async { let date = Date() let store = TestStore( @@ -412,9 +422,10 @@ final class VoiceMemosTests: XCTestCase { } } + @MainActor func testDeleteMemoWhilePlaying() async { let url = URL(fileURLWithPath: "pointfreeco/functions.m4a") - + let clock = TestClock() let store = TestStore( initialState: VoiceMemos.State( voiceMemos: [ @@ -431,7 +442,7 @@ final class VoiceMemosTests: XCTestCase { VoiceMemos() } withDependencies: { $0.audioPlayer.play = { @Sendable _ in try await Task.never() } - $0.continuousClock = self.clock + $0.continuousClock = clock } await store.send(\.voiceMemos[id:url].playButtonTapped) { diff --git a/Sources/ComposableArchitectureMacros/Extensions.swift b/Sources/ComposableArchitectureMacros/Extensions.swift index 980c0b1ad9a8..84ec48bf6368 100644 --- a/Sources/ComposableArchitectureMacros/Extensions.swift +++ b/Sources/ComposableArchitectureMacros/Extensions.swift @@ -40,27 +40,15 @@ extension VariableDeclSyntax { } func accessorsMatching(_ predicate: (TokenKind) -> Bool) -> [AccessorDeclSyntax] { - let patternBindings = bindings.compactMap { binding in - binding.as(PatternBindingSyntax.self) - } - let accessors: [AccessorDeclListSyntax.Element] = patternBindings.compactMap { patternBinding in + let accessors: [AccessorDeclListSyntax.Element] = bindings.compactMap { patternBinding in switch patternBinding.accessorBlock?.accessors { - case .accessors(let accessors): + case let .accessors(accessors): return accessors default: return nil } }.flatMap { $0 } - return accessors.compactMap { accessor in - guard let decl = accessor.as(AccessorDeclSyntax.self) else { - return nil - } - if predicate(decl.accessorSpecifier.tokenKind) { - return decl - } else { - return nil - } - } + return accessors.compactMap { predicate($0.accessorSpecifier.tokenKind) ? $0 : nil } } var willSetAccessors: [AccessorDeclSyntax] { @@ -229,7 +217,7 @@ extension DeclGroupSyntax { var memberFunctionStandins: [FunctionDeclSyntax.SignatureStandin] { var standins = [FunctionDeclSyntax.SignatureStandin]() for member in memberBlock.members { - if let function = member.as(MemberBlockItemSyntax.self)?.decl.as(FunctionDeclSyntax.self) { + if let function = member.decl.as(FunctionDeclSyntax.self) { standins.append(function.signatureStandin) } } @@ -238,7 +226,7 @@ extension DeclGroupSyntax { func hasMemberFunction(equvalentTo other: FunctionDeclSyntax) -> Bool { for member in memberBlock.members { - if let function = member.as(MemberBlockItemSyntax.self)?.decl.as(FunctionDeclSyntax.self) { + if let function = member.decl.as(FunctionDeclSyntax.self) { if function.isEquivalent(to: other) { return true } @@ -249,7 +237,7 @@ extension DeclGroupSyntax { func hasMemberProperty(equivalentTo other: VariableDeclSyntax) -> Bool { for member in memberBlock.members { - if let variable = member.as(MemberBlockItemSyntax.self)?.decl.as(VariableDeclSyntax.self) { + if let variable = member.decl.as(VariableDeclSyntax.self) { if variable.isEquivalent(to: other) { return true } @@ -260,7 +248,7 @@ extension DeclGroupSyntax { var definedVariables: [VariableDeclSyntax] { memberBlock.members.compactMap { member in - if let variableDecl = member.as(MemberBlockItemSyntax.self)?.decl.as(VariableDeclSyntax.self) + if let variableDecl = member.decl.as(VariableDeclSyntax.self) { return variableDecl } diff --git a/Sources/ComposableArchitectureMacros/ReducerMacro.swift b/Sources/ComposableArchitectureMacros/ReducerMacro.swift index 0c621f9238ee..15164df3852d 100644 --- a/Sources/ComposableArchitectureMacros/ReducerMacro.swift +++ b/Sources/ComposableArchitectureMacros/ReducerMacro.swift @@ -192,14 +192,14 @@ extension ReducerMacro: MemberMacro { ) throws -> [DeclSyntax] { let access = declaration.modifiers.first { $0.name.tokenKind == .keyword(.public) } let typeNames = declaration.memberBlock.members.compactMap { - $0.as(MemberBlockItemSyntax.self)?.decl.as(StructDeclSyntax.self)?.name.text - ?? $0.as(MemberBlockItemSyntax.self)?.decl.as(TypeAliasDeclSyntax.self)?.name.text - ?? $0.as(MemberBlockItemSyntax.self)?.decl.as(EnumDeclSyntax.self)?.name.text + $0.decl.as(StructDeclSyntax.self)?.name.text + ?? $0.decl.as(TypeAliasDeclSyntax.self)?.name.text + ?? $0.decl.as(EnumDeclSyntax.self)?.name.text } let hasState = typeNames.contains("State") let hasAction = typeNames.contains("Action") let bindings = declaration.memberBlock.members.flatMap { - $0.as(MemberBlockItemSyntax.self)?.decl.as(VariableDeclSyntax.self)?.bindings ?? [] + $0.decl.as(VariableDeclSyntax.self)?.bindings ?? [] } let hasReduceMethod = declaration.memberBlock.members.contains { guard @@ -371,7 +371,7 @@ extension ReducerMacro: MemberMacro { ) } if !declaration.memberBlock.members.contains( - where: { $0.as(FunctionDeclSyntax.self)?.name.text == "scope" } + where: { $0.decl.as(FunctionDeclSyntax.self)?.name.text == "scope" } ) { decls.append( """ diff --git a/Sources/ComposableArchitectureMacros/ViewActionMacro.swift b/Sources/ComposableArchitectureMacros/ViewActionMacro.swift index 8053cdc168d0..04397dd20849 100644 --- a/Sources/ComposableArchitectureMacros/ViewActionMacro.swift +++ b/Sources/ComposableArchitectureMacros/ViewActionMacro.swift @@ -85,10 +85,7 @@ extension SyntaxProtocol { if let sendExpression = functionCall.sendExpression { var fixIt: FixIt? if let outer = functionCall.arguments.first, - let inner = - outer - .as(LabeledExprSyntax.self)?.expression - .as(FunctionCallExprSyntax.self), + let inner = outer.expression.as(FunctionCallExprSyntax.self), inner.calledExpression .as(MemberAccessExprSyntax.self)?.declName.baseName.text == "view", inner.arguments.count == 1 diff --git a/Tests/ComposableArchitectureTests/BindableStoreTests.swift b/Tests/ComposableArchitectureTests/BindableStoreTests.swift index 324333a15091..7ea5f4f2926a 100644 --- a/Tests/ComposableArchitectureTests/BindableStoreTests.swift +++ b/Tests/ComposableArchitectureTests/BindableStoreTests.swift @@ -3,9 +3,9 @@ import Combine import SwiftUI import XCTest -@MainActor @available(*, deprecated, message: "TODO: Update to use case pathable syntax with Swift 5.9") final class BindableStoreTests: XCTestCase { + @MainActor func testBindableStore() { struct BindableReducer: Reducer { struct State: Equatable { @@ -82,6 +82,7 @@ final class BindableStoreTests: XCTestCase { } } + @MainActor func testTestStoreBindings() async { struct LoginFeature: Reducer { struct State: Equatable { @@ -144,6 +145,7 @@ final class BindableStoreTests: XCTestCase { XCTAssertTrue(LoginViewState(store.bindings).isLoginButtonDisabled) } + @MainActor func testTestStoreBindings_ViewAction() async { struct LoginFeature: Reducer { struct State: Equatable { diff --git a/Tests/ComposableArchitectureTests/BindingLocalTests.swift b/Tests/ComposableArchitectureTests/BindingLocalTests.swift index 782a11bfa362..0eb72a1681e4 100644 --- a/Tests/ComposableArchitectureTests/BindingLocalTests.swift +++ b/Tests/ComposableArchitectureTests/BindingLocalTests.swift @@ -3,8 +3,8 @@ @testable import ComposableArchitecture - @MainActor final class BindingLocalTests: BaseTCATestCase { + @MainActor public func testBindingLocalIsActive() { XCTAssertFalse(BindingLocal.isActive) diff --git a/Tests/ComposableArchitectureTests/CompatibilityTests.swift b/Tests/ComposableArchitectureTests/CompatibilityTests.swift index 676fef433271..2eb7679ee55a 100644 --- a/Tests/ComposableArchitectureTests/CompatibilityTests.swift +++ b/Tests/ComposableArchitectureTests/CompatibilityTests.swift @@ -2,13 +2,11 @@ import Combine import ComposableArchitecture import XCTest -@MainActor final class CompatibilityTests: BaseTCATestCase { - var cancellables: Set = [] - // Actions can be re-entrantly sent into the store if an action is sent that holds an object // which sends an action on deinit. In order to prevent a simultaneous access exception for this // case we need to use `withExtendedLifetime` on the buffered actions when clearing them out. + @MainActor func testCaseStudy_ActionReentranceFromClearedBufferCausingDeinitAction() { let cancelID = UUID() @@ -81,7 +79,10 @@ final class CompatibilityTests: BaseTCATestCase { // In particular, this means that in the implementation of `Store.send` we need to flip // `isSending` to false _after_ the store's state mutation is made so that re-entrant actions // are buffered rather than immediately handled. + @MainActor func testCaseStudy_ActionReentranceFromStateObservation() { + var cancellables: Set = [] + let store = Store(initialState: 0) { Reduce { state, action in state = action @@ -97,14 +98,14 @@ final class CompatibilityTests: BaseTCATestCase { viewStore.send(0) } } - .store(in: &self.cancellables) + .store(in: &cancellables) var stateChanges: [Int] = [] viewStore.publisher .sink { stateChanges.append($0) } - .store(in: &self.cancellables) + .store(in: &cancellables) XCTAssertEqual(stateChanges, [0]) viewStore.send(1) diff --git a/Tests/ComposableArchitectureTests/ComposableArchitectureTests.swift b/Tests/ComposableArchitectureTests/ComposableArchitectureTests.swift index 6df14ff6e552..60fd987f6945 100644 --- a/Tests/ComposableArchitectureTests/ComposableArchitectureTests.swift +++ b/Tests/ComposableArchitectureTests/ComposableArchitectureTests.swift @@ -3,10 +3,8 @@ import CombineSchedulers import ComposableArchitecture import XCTest -@MainActor final class ComposableArchitectureTests: BaseTCATestCase { - var cancellables: Set = [] - + @MainActor func testScheduling() async { struct Counter: Reducer { typealias State = Int @@ -69,14 +67,17 @@ final class ComposableArchitectureTests: BaseTCATestCase { await store.receive(.squareNow) { $0 = 391876 } } + @MainActor func testSimultaneousWorkOrdering() { + var cancellables: Set = [] + let mainQueue = DispatchQueue.test var values: [Int] = [] mainQueue.schedule(after: mainQueue.now, interval: 1) { values.append(1) } - .store(in: &self.cancellables) + .store(in: &cancellables) mainQueue.schedule(after: mainQueue.now, interval: 2) { values.append(42) } - .store(in: &self.cancellables) + .store(in: &cancellables) XCTAssertEqual(values, []) mainQueue.advance() @@ -85,6 +86,7 @@ final class ComposableArchitectureTests: BaseTCATestCase { XCTAssertEqual(values, [1, 42, 1, 1, 42]) } + @MainActor func testLongLivingEffects() async { enum Action { case end, incr, start } @@ -117,6 +119,7 @@ final class ComposableArchitectureTests: BaseTCATestCase { await store.send(.end) } + @MainActor func testCancellation() async { let mainQueue = DispatchQueue.test diff --git a/Tests/ComposableArchitectureTests/DependencyKeyWritingReducerTests.swift b/Tests/ComposableArchitectureTests/DependencyKeyWritingReducerTests.swift index 7fb50c82e2df..fc2e15945846 100644 --- a/Tests/ComposableArchitectureTests/DependencyKeyWritingReducerTests.swift +++ b/Tests/ComposableArchitectureTests/DependencyKeyWritingReducerTests.swift @@ -2,7 +2,6 @@ import ComposableArchitecture import XCTest - @MainActor final class DependencyKeyWritingReducerTests: BaseTCATestCase { func testWritingFusion() async { let reducer: _DependencyKeyWritingReducer = Feature() @@ -26,6 +25,7 @@ XCTAssertTrue((reducer as Any) is _DependencyKeyWritingReducer) } + @MainActor func testWritingFusionOrder() async { let store = TestStore(initialState: Feature.State()) { Feature() @@ -38,6 +38,7 @@ } } + @MainActor func testTransformFusionOrder() async { let store = TestStore(initialState: Feature.State()) { Feature() @@ -50,6 +51,7 @@ } } + @MainActor func testWritingOrder() async { let store = TestStore(initialState: Feature.State()) { CombineReducers { @@ -64,6 +66,7 @@ } } + @MainActor func testTransformOrder() async { let store = TestStore(initialState: Feature.State()) { CombineReducers { @@ -106,6 +109,7 @@ } } } + @MainActor func testDependency_EffectOfEffect() async { let store = TestStore(initialState: Feature_testDependency_EffectOfEffect.State()) { Feature_testDependency_EffectOfEffect() diff --git a/Tests/ComposableArchitectureTests/EffectDebounceTests.swift b/Tests/ComposableArchitectureTests/EffectDebounceTests.swift index 5af3c56b24f4..cf8bdde44545 100644 --- a/Tests/ComposableArchitectureTests/EffectDebounceTests.swift +++ b/Tests/ComposableArchitectureTests/EffectDebounceTests.swift @@ -2,10 +2,8 @@ import Combine @_spi(Internals) import ComposableArchitecture import XCTest -@MainActor final class EffectDebounceTests: BaseTCATestCase { - var cancellables: Set = [] - + @MainActor func testDebounce() async { let mainQueue = DispatchQueue.test var values: [Int] = [] @@ -56,6 +54,7 @@ final class EffectDebounceTests: BaseTCATestCase { XCTAssertEqual(values, [3]) } + @MainActor func testDebounceIsLazy() async { let mainQueue = DispatchQueue.test var values: [Int] = [] diff --git a/Tests/ComposableArchitectureTests/EffectFailureTests.swift b/Tests/ComposableArchitectureTests/EffectFailureTests.swift index 1e6a9136cd99..cd9a8b9bb743 100644 --- a/Tests/ComposableArchitectureTests/EffectFailureTests.swift +++ b/Tests/ComposableArchitectureTests/EffectFailureTests.swift @@ -3,10 +3,8 @@ @_spi(Internals) import ComposableArchitecture import XCTest - @MainActor final class EffectFailureTests: BaseTCATestCase { - var cancellables: Set = [] - + @MainActor func testRunUnexpectedThrows() async { guard #available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) else { return } diff --git a/Tests/ComposableArchitectureTests/EffectOperationTests.swift b/Tests/ComposableArchitectureTests/EffectOperationTests.swift index c9b5f5eb93ca..cdd80e9a0259 100644 --- a/Tests/ComposableArchitectureTests/EffectOperationTests.swift +++ b/Tests/ComposableArchitectureTests/EffectOperationTests.swift @@ -3,8 +3,8 @@ @testable import ComposableArchitecture - @MainActor class EffectOperationTests: BaseTCATestCase { + @MainActor func testMergeDiscardsNones() async { var effect = Effect.none .merge(with: .none) @@ -52,6 +52,7 @@ } } + @MainActor func testConcatenateDiscardsNones() async { var effect = Effect.none .concatenate(with: .none) @@ -99,6 +100,7 @@ } } + @MainActor func testMergeFuses() async { var values = [Int]() @@ -122,6 +124,7 @@ XCTAssertEqual(values, [42, 1729]) } + @MainActor func testConcatenateFuses() async { var values = [Int]() @@ -137,6 +140,7 @@ XCTAssertEqual(values, [42, 1729]) } + @MainActor func testMap() async { let effect = Effect.run { send in await send(42) } .map { "\($0)" } diff --git a/Tests/ComposableArchitectureTests/EffectRunTests.swift b/Tests/ComposableArchitectureTests/EffectRunTests.swift index 81f96e460681..bf909461c2a8 100644 --- a/Tests/ComposableArchitectureTests/EffectRunTests.swift +++ b/Tests/ComposableArchitectureTests/EffectRunTests.swift @@ -2,8 +2,8 @@ import Combine import ComposableArchitecture import XCTest -@MainActor final class EffectRunTests: BaseTCATestCase { + @MainActor func testRun() async { struct State: Equatable {} enum Action: Equatable { case tapped, response } @@ -21,6 +21,7 @@ final class EffectRunTests: BaseTCATestCase { await store.receive(.response) } + @MainActor func testRunCatch() async { struct State: Equatable {} enum Action: Equatable { case tapped, response } @@ -44,6 +45,7 @@ final class EffectRunTests: BaseTCATestCase { } #if DEBUG + @MainActor func testRunUnhandledFailure() async { var line: UInt! XCTExpectFailure(nil, enabled: nil, strict: nil) { @@ -77,6 +79,7 @@ final class EffectRunTests: BaseTCATestCase { } #endif + @MainActor func testRunCancellation() async { enum CancelID { case response } struct State: Equatable {} @@ -99,6 +102,7 @@ final class EffectRunTests: BaseTCATestCase { await store.send(.tapped).finish() } + @MainActor func testRunCancellationCatch() async { enum CancelID { case responseA } struct State: Equatable {} @@ -124,6 +128,7 @@ final class EffectRunTests: BaseTCATestCase { } #if DEBUG + @MainActor func testRunEscapeFailure() async { XCTExpectFailure { $0.compactDescription == """ diff --git a/Tests/ComposableArchitectureTests/EffectTests.swift b/Tests/ComposableArchitectureTests/EffectTests.swift index 97522266457e..c78c3f352145 100644 --- a/Tests/ComposableArchitectureTests/EffectTests.swift +++ b/Tests/ComposableArchitectureTests/EffectTests.swift @@ -3,7 +3,6 @@ @_spi(Canary) @_spi(Internals) import ComposableArchitecture import XCTest - @MainActor final class EffectTests: BaseTCATestCase { var cancellables: Set = [] let mainQueue = DispatchQueue.test @@ -148,6 +147,7 @@ } } } + @MainActor func testDependenciesTransferredToEffects_Task() async { let store = TestStore(initialState: 0) { Feature_testDependenciesTransferredToEffects_Task() @@ -181,6 +181,7 @@ } } } + @MainActor func testDependenciesTransferredToEffects_Run() async { let store = TestStore(initialState: 0) { Feature_testDependenciesTransferredToEffects_Run() diff --git a/Tests/ComposableArchitectureTests/ObservableTests.swift b/Tests/ComposableArchitectureTests/ObservableTests.swift index 7186653631c1..cf9de059983a 100644 --- a/Tests/ComposableArchitectureTests/ObservableTests.swift +++ b/Tests/ComposableArchitectureTests/ObservableTests.swift @@ -3,7 +3,6 @@ import ComposableArchitecture import XCTest - @MainActor final class ObservableTests: BaseTCATestCase { func testBasics() async { var state = ChildState() @@ -281,6 +280,7 @@ XCTAssertEqual(state.sibling.count, 2) } + @MainActor func testStore_ReplaceChild() async { let store = Store(initialState: ParentState()) { Reduce { state, _ in @@ -301,6 +301,7 @@ XCTAssertEqual(store.child.count, 42) } + @MainActor func testStore_Replace() async { let store = Store(initialState: ChildState()) { Reduce { state, _ in @@ -321,6 +322,7 @@ XCTAssertEqual(store.count, 42) } + @MainActor func testStore_ResetChild() async { let store = Store(initialState: ParentState(child: ChildState(count: 42))) { @@ -342,6 +344,7 @@ XCTAssertEqual(store.child.count, 0) } + @MainActor func testStore_Reset() async { let store = Store(initialState: ChildState(count: 42)) { Reduce { state, _ in diff --git a/Tests/ComposableArchitectureTests/ObserveTests.swift b/Tests/ComposableArchitectureTests/ObserveTests.swift index eb3f1e14824d..ccffe6dafde0 100644 --- a/Tests/ComposableArchitectureTests/ObserveTests.swift +++ b/Tests/ComposableArchitectureTests/ObserveTests.swift @@ -3,7 +3,6 @@ import ComposableArchitecture import XCTest - @MainActor final class ObserveTests: BaseTCATestCase { func testObserve() async throws { let model = Model() diff --git a/Tests/ComposableArchitectureTests/ReducerTests.swift b/Tests/ComposableArchitectureTests/ReducerTests.swift index 90647c6539e6..9cfed321d319 100644 --- a/Tests/ComposableArchitectureTests/ReducerTests.swift +++ b/Tests/ComposableArchitectureTests/ReducerTests.swift @@ -5,7 +5,6 @@ import XCTest import os.signpost - @MainActor final class ReducerTests: BaseTCATestCase { var cancellables: Set = [] @@ -38,6 +37,7 @@ } } } + @MainActor func testCombine_EffectsAreMerged() async throws { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { var fastValue: Int? = nil @@ -84,6 +84,7 @@ } } } + @MainActor func testCombine() async { var first = false var second = false diff --git a/Tests/ComposableArchitectureTests/Reducers/BindingReducerTests.swift b/Tests/ComposableArchitectureTests/Reducers/BindingReducerTests.swift index e3679a07dd9f..447c1882e612 100644 --- a/Tests/ComposableArchitectureTests/Reducers/BindingReducerTests.swift +++ b/Tests/ComposableArchitectureTests/Reducers/BindingReducerTests.swift @@ -2,7 +2,6 @@ import ComposableArchitecture import XCTest - @MainActor final class BindingTests: BaseTCATestCase { @Reducer struct BindingTest { @@ -49,6 +48,7 @@ ) } + @MainActor func testViewEquality() { struct Feature: Reducer { struct State: Equatable { @@ -76,6 +76,7 @@ XCTAssertEqual(count.wrappedValue, 1) } + @MainActor func testNestedBindingState() { let store = Store(initialState: BindingTest.State()) { BindingTest() } @@ -86,6 +87,7 @@ XCTAssertEqual(viewStore.state, .init(nested: .init(field: "Hello!"))) } + @MainActor func testNestedBindingViewState() { struct ViewState: Equatable { @BindingViewState var field: String @@ -100,6 +102,7 @@ XCTAssertEqual(store.withState { $0.nested.field }, "Hello!") } + @MainActor func testBindingActionUpdatesRespectsPatternMatching() async { let testStore = TestStore( initialState: BindingTest.State(nested: BindingTest.State.Nested(field: "")) diff --git a/Tests/ComposableArchitectureTests/Reducers/ForEachReducerTests.swift b/Tests/ComposableArchitectureTests/Reducers/ForEachReducerTests.swift index 3b8ccd44463a..f6f1d9fbefdc 100644 --- a/Tests/ComposableArchitectureTests/Reducers/ForEachReducerTests.swift +++ b/Tests/ComposableArchitectureTests/Reducers/ForEachReducerTests.swift @@ -2,8 +2,8 @@ import ComposableArchitecture import XCTest - @MainActor final class ForEachReducerTests: BaseTCATestCase { + @MainActor func testElementAction() async { let store = TestStore( initialState: Elements.State( @@ -28,6 +28,7 @@ } } + @MainActor func testNonElementAction() async { let store = TestStore(initialState: Elements.State()) { Elements() @@ -37,6 +38,7 @@ } #if DEBUG + @MainActor func testMissingElement() async { let store = TestStore(initialState: Elements.State()) { EmptyReducer() @@ -70,6 +72,7 @@ } #endif + @MainActor func testAutomaticEffectCancellation() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Timer: Reducer { diff --git a/Tests/ComposableArchitectureTests/Reducers/IfCaseLetReducerTests.swift b/Tests/ComposableArchitectureTests/Reducers/IfCaseLetReducerTests.swift index e9c87cd8f2ec..fe0838a38e2c 100644 --- a/Tests/ComposableArchitectureTests/Reducers/IfCaseLetReducerTests.swift +++ b/Tests/ComposableArchitectureTests/Reducers/IfCaseLetReducerTests.swift @@ -1,9 +1,9 @@ import ComposableArchitecture import XCTest -@MainActor @available(*, deprecated, message: "TODO: Update to use case pathable syntax with Swift 5.9") final class IfCaseLetReducerTests: BaseTCATestCase { + @MainActor func testChildAction() async { struct SomeError: Error, Equatable {} @@ -32,6 +32,7 @@ final class IfCaseLetReducerTests: BaseTCATestCase { } #if DEBUG + @MainActor func testNilChild() async { struct SomeError: Error, Equatable {} @@ -70,6 +71,7 @@ final class IfCaseLetReducerTests: BaseTCATestCase { } #endif + @MainActor func testEffectCancellation_Siblings() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Child: Reducer { @@ -150,6 +152,7 @@ final class IfCaseLetReducerTests: BaseTCATestCase { } } + @MainActor func testIdentifiableChild() async { struct Feature: Reducer { enum State: Equatable { diff --git a/Tests/ComposableArchitectureTests/Reducers/IfLetReducerTests.swift b/Tests/ComposableArchitectureTests/Reducers/IfLetReducerTests.swift index 796e33bab3f1..856c42b5298d 100644 --- a/Tests/ComposableArchitectureTests/Reducers/IfLetReducerTests.swift +++ b/Tests/ComposableArchitectureTests/Reducers/IfLetReducerTests.swift @@ -1,10 +1,10 @@ import ComposableArchitecture import XCTest -@MainActor @available(*, deprecated, message: "TODO: Update to use case pathable syntax with Swift 5.9") final class IfLetReducerTests: BaseTCATestCase { #if DEBUG + @MainActor func testNilChild() async { let store = TestStore(initialState: Int?.none) { EmptyReducer() @@ -40,6 +40,7 @@ final class IfLetReducerTests: BaseTCATestCase { } #endif + @MainActor func testEffectCancellation() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Child: Reducer { @@ -117,6 +118,7 @@ final class IfLetReducerTests: BaseTCATestCase { } } + @MainActor func testGrandchildEffectCancellation() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct GrandChild: Reducer { @@ -209,6 +211,7 @@ final class IfLetReducerTests: BaseTCATestCase { } } + @MainActor func testEphemeralState() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Parent: Reducer { @@ -246,6 +249,7 @@ final class IfLetReducerTests: BaseTCATestCase { } } + @MainActor func testIdentifiableChild() async { struct Feature: Reducer { struct State: Equatable { @@ -314,6 +318,7 @@ final class IfLetReducerTests: BaseTCATestCase { } } + @MainActor func testEphemeralDismissal() async { struct Feature: Reducer { struct State: Equatable { diff --git a/Tests/ComposableArchitectureTests/Reducers/OnChangeReducerTests.swift b/Tests/ComposableArchitectureTests/Reducers/OnChangeReducerTests.swift index d3f396eb1f21..e22c59333731 100644 --- a/Tests/ComposableArchitectureTests/Reducers/OnChangeReducerTests.swift +++ b/Tests/ComposableArchitectureTests/Reducers/OnChangeReducerTests.swift @@ -1,9 +1,9 @@ import ComposableArchitecture import XCTest -@MainActor @available(*, deprecated, message: "TODO: Update to use case pathable syntax with Swift 5.9") final class OnChangeReducerTests: BaseTCATestCase { + @MainActor func testOnChange() async { struct Feature: Reducer { struct State: Equatable { @@ -48,6 +48,7 @@ final class OnChangeReducerTests: BaseTCATestCase { } } + @MainActor func testOnChangeChildStates() async { struct Feature: Reducer { struct ChildFeature: Reducer { @@ -139,6 +140,7 @@ final class OnChangeReducerTests: BaseTCATestCase { } } + @MainActor func testOnChangeTuple() async { struct Feature: Reducer { struct State: Equatable { diff --git a/Tests/ComposableArchitectureTests/Reducers/PresentationReducerTests.swift b/Tests/ComposableArchitectureTests/Reducers/PresentationReducerTests.swift index 4458eb6a2d4c..c5accdd862a3 100644 --- a/Tests/ComposableArchitectureTests/Reducers/PresentationReducerTests.swift +++ b/Tests/ComposableArchitectureTests/Reducers/PresentationReducerTests.swift @@ -1,9 +1,9 @@ import ComposableArchitecture import XCTest -@MainActor @available(*, deprecated, message: "TODO: Update to use case pathable syntax with Swift 5.9") final class PresentationReducerTests: BaseTCATestCase { + @MainActor func testPresentationStateSubscriptCase() { enum Child: Equatable { case int(Int) @@ -24,6 +24,7 @@ final class PresentationReducerTests: BaseTCATestCase { } #if DEBUG + @MainActor func testPresentationStateSubscriptCase_Unexpected() { enum Child: Equatable { case int(Int) @@ -56,6 +57,7 @@ final class PresentationReducerTests: BaseTCATestCase { } #endif + @MainActor func testPresentation_parentDismissal() async { struct Child: Reducer { struct State: Equatable { @@ -120,6 +122,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_parentDismissal_NilOut() async { struct Child: Reducer { struct State: Equatable { @@ -188,6 +191,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_childDismissal() async { struct Child: Reducer { struct State: Equatable { @@ -264,6 +268,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_parentDismissal_effects() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Child: Reducer { @@ -344,6 +349,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_childDismissal_effects() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Child: Reducer { @@ -432,6 +438,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_identifiableDismissal_effects() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Child: Reducer { @@ -519,6 +526,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_LeavePresented() async { struct Child: Reducer { struct State: Equatable {} @@ -561,6 +569,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_LeavePresented_FinishStore() async { struct Child: Reducer { struct State: Equatable {} @@ -604,6 +613,7 @@ final class PresentationReducerTests: BaseTCATestCase { await store.finish() } + @MainActor func testInertPresentation() async { if #available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) { struct Parent: Reducer { @@ -644,6 +654,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testInertPresentation_dismissal() async { if #available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) { struct Parent: Reducer { @@ -687,6 +698,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testInertPresentation_automaticDismissal() async { if #available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) { struct Parent: Reducer { @@ -745,6 +757,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_hydratedDestination_childDismissal() async { struct Child: Reducer { struct State: Equatable { @@ -808,6 +821,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_rehydratedDestination_childDismissal() async { struct ChildFeature: Reducer { struct State: Equatable {} @@ -875,6 +889,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testEnumPresentation() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Child: Reducer { @@ -1054,6 +1069,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testNavigation_cancelID_childCancellation() async { struct Child: Reducer { struct State: Equatable {} @@ -1112,6 +1128,7 @@ final class PresentationReducerTests: BaseTCATestCase { await presentationTask.cancel() } + @MainActor func testNavigation_cancelID_parentCancellation() async { struct Grandchild: Reducer { struct State: Equatable {} @@ -1209,6 +1226,7 @@ final class PresentationReducerTests: BaseTCATestCase { await childPresentationTask.cancel() } + @MainActor func testNavigation_cancelID_parentCancelTwoChildren() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Child: Reducer { @@ -1304,6 +1322,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testNavigation_cancelID_childCannotCancelSibling() async throws { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Child: Reducer { @@ -1406,6 +1425,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testNavigation_cancelID_childCannotCancelIdentifiableSibling() async throws { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Child: Reducer { @@ -1511,6 +1531,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testNavigation_cancelID_childCannotCancelParent() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Child: Reducer { @@ -1591,6 +1612,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testNavigation_cancelID_parentDismissGrandchild() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Grandchild: Reducer { @@ -1697,6 +1719,7 @@ final class PresentationReducerTests: BaseTCATestCase { } #if DEBUG + @MainActor func testRuntimeWarn_NilChild_SendDismissAction() async { struct Child: Reducer { struct State: Equatable {} @@ -1754,6 +1777,7 @@ final class PresentationReducerTests: BaseTCATestCase { #endif #if DEBUG + @MainActor func testRuntimeWarn_NilChild_SendChildAction() async { struct Child: Reducer { struct State: Equatable {} @@ -1812,6 +1836,7 @@ final class PresentationReducerTests: BaseTCATestCase { } #endif + @MainActor func testRehydrateSameChild_SendDismissAction() async { struct Child: Reducer { struct State: Equatable {} @@ -1853,6 +1878,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testRehydrateDifferentChild_SendDismissAction() async { struct Child: Reducer { struct State: Equatable, Identifiable { @@ -1908,6 +1934,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_parentNilsOutChildWithLongLivingEffect() async { struct Child: Reducer { struct State: Equatable { @@ -1975,6 +2002,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_DestinationEnum_IdentityChange() async { struct Child: Reducer { struct State: Equatable, Identifiable { @@ -2077,6 +2105,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testAlertThenDialog() async { if #available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) { struct Feature: Reducer { @@ -2179,6 +2208,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_leaveChildPresented() async { struct Child: Reducer { struct State: Equatable {} @@ -2221,6 +2251,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testPresentation_leaveChildPresented_WithLongLivingEffect() async { struct Child: Reducer { struct State: Equatable {} @@ -2293,6 +2324,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testCancelInFlightEffects() async { struct Child: Reducer { struct State: Equatable { @@ -2381,6 +2413,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testOuterCancellation() async { struct Child: Reducer { struct State: Equatable {} @@ -2475,6 +2508,7 @@ final class PresentationReducerTests: BaseTCATestCase { await store.send(.tapAfter) } + @MainActor func testPresentation_leaveAlertPresentedForNonAlertActions() async { if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) { struct Child: Reducer { @@ -2591,6 +2625,7 @@ final class PresentationReducerTests: BaseTCATestCase { } } + @MainActor func testFastPathEquality() { struct State: Equatable { static func == (lhs: Self, rhs: Self) -> Bool { diff --git a/Tests/ComposableArchitectureTests/Reducers/StackReducerTests.swift b/Tests/ComposableArchitectureTests/Reducers/StackReducerTests.swift index c34a72efbb5d..100d848e2dcf 100644 --- a/Tests/ComposableArchitectureTests/Reducers/StackReducerTests.swift +++ b/Tests/ComposableArchitectureTests/Reducers/StackReducerTests.swift @@ -2,8 +2,8 @@ @_spi(Internals) import ComposableArchitecture import XCTest - @MainActor final class StackReducerTests: BaseTCATestCase { + @MainActor func testStackStateSubscriptCase() { enum Element: Equatable { case int(Int) @@ -19,6 +19,7 @@ } #if DEBUG + @MainActor func testStackStateSubscriptCase_Unexpected() { enum Element: Equatable { case int(Int) @@ -47,6 +48,7 @@ } #endif + @MainActor func testCustomDebugStringConvertible() { @Dependency(\.stackElementID) var stackElementID XCTAssertEqual(stackElementID.peek().generation, 0) @@ -62,6 +64,7 @@ } } + @MainActor func testPresent() async { struct Child: Reducer { struct State: Equatable { @@ -117,6 +120,7 @@ } } + @MainActor func testDismissFromParent() async { struct Child: Reducer { struct State: Equatable {} @@ -175,6 +179,7 @@ } } + @MainActor func testDismissFromChild() async { struct Child: Reducer { struct State: Equatable {} @@ -236,6 +241,7 @@ } } + @MainActor func testDismissReceiveWrongAction() async { struct Child: Reducer { struct State: Equatable {} @@ -282,6 +288,7 @@ } } + @MainActor func testDismissFromIntermediateChild() async { struct Child: Reducer { struct State: Equatable { var count = 0 } @@ -346,6 +353,7 @@ } } + @MainActor func testDismissFromDeepLinkedChild() async { struct Child: Reducer { struct State: Equatable {} @@ -400,6 +408,7 @@ } } + @MainActor func testEnumChild() async { struct Child: Reducer { struct State: Equatable { @@ -491,6 +500,7 @@ } } + @MainActor func testParentDismiss() async { struct Child: Reducer { struct State: Equatable {} @@ -621,6 +631,7 @@ } } } + @MainActor func testSiblingCannotCancel() async { var path = StackState() path.append(.child1(TestSiblingCannotCancel.Child.State())) @@ -720,6 +731,7 @@ } } } + @MainActor func testFirstChildWhileEffectInFlight_DeliversToCorrectID() async { let mainQueue = DispatchQueue.test let store = TestStore( @@ -761,6 +773,7 @@ } #if DEBUG + @MainActor func testSendActionWithIDThatDoesNotExist() async { struct Parent: Reducer { struct State: Equatable { @@ -811,6 +824,7 @@ #endif #if DEBUG + @MainActor func testPopIDThatDoesNotExist() async { struct Parent: Reducer { struct State: Equatable { @@ -846,6 +860,7 @@ #endif #if DEBUG + @MainActor func testChildWithInFlightEffect() async { struct Child: Reducer { struct State: Equatable {} @@ -905,6 +920,7 @@ } #endif + @MainActor func testMultipleChildEffects() async { struct Child: Reducer { struct State: Equatable { var count = 0 } @@ -967,6 +983,7 @@ } } + @MainActor func testChildEffectCancellation() async { struct Child: Reducer { struct State: Equatable {} @@ -1006,6 +1023,7 @@ } } + @MainActor func testPush() async { struct Child: Reducer { struct State: Equatable {} @@ -1061,6 +1079,7 @@ } #if DEBUG + @MainActor func testPushReusedID() async { struct Child: Reducer { struct State: Equatable {} @@ -1107,6 +1126,7 @@ #endif #if DEBUG + @MainActor func testPushIDGreaterThanNextGeneration() async { struct Child: Reducer { struct State: Equatable {} @@ -1151,6 +1171,7 @@ } #endif + @MainActor func testMismatchedIDFailure() async { struct Child: Reducer { struct State: Equatable {} @@ -1194,6 +1215,7 @@ } } + @MainActor func testSendCopiesStackElementIDGenerator() async { struct Feature: Reducer { struct State: Equatable { @@ -1247,6 +1269,7 @@ } } + @MainActor func testOuterCancellation() async { struct Child: Reducer { struct State: Equatable {} diff --git a/Tests/ComposableArchitectureTests/RuntimeWarningTests.swift b/Tests/ComposableArchitectureTests/RuntimeWarningTests.swift index 993631791d4c..bee2a6c1188f 100644 --- a/Tests/ComposableArchitectureTests/RuntimeWarningTests.swift +++ b/Tests/ComposableArchitectureTests/RuntimeWarningTests.swift @@ -3,8 +3,8 @@ import ComposableArchitecture import XCTest - @MainActor final class RuntimeWarningTests: BaseTCATestCase { + @MainActor func testStoreCreationMainThread() async { uncheckedUseMainSerialExecutor = false XCTExpectFailure { @@ -22,6 +22,7 @@ .value } + @MainActor func testEffectFinishedMainThread() async throws { XCTExpectFailure { $0.compactDescription == """ @@ -104,6 +105,7 @@ } #if os(macOS) + @MainActor func testEffectEmitMainThread() async throws { try XCTSkipIf(ProcessInfo.processInfo.environment["CI"] != nil) XCTExpectFailure { @@ -176,6 +178,7 @@ } #endif + @MainActor func testBindingUnhandledAction() { let line = #line + 2 struct State: Equatable { @@ -201,6 +204,7 @@ } } + @MainActor func testBindingUnhandledAction_BindingState() { struct State: Equatable { @BindingState var value = 0 diff --git a/Tests/ComposableArchitectureTests/ScopeCacheTests.swift b/Tests/ComposableArchitectureTests/ScopeCacheTests.swift index 2bc11578a497..4d89de27a338 100644 --- a/Tests/ComposableArchitectureTests/ScopeCacheTests.swift +++ b/Tests/ComposableArchitectureTests/ScopeCacheTests.swift @@ -2,9 +2,9 @@ @_spi(Internals) import ComposableArchitecture import XCTest - @MainActor final class ScopeCacheTests: BaseTCATestCase { @available(*, deprecated) + @MainActor func testOptionalScope_UncachedStore() { #if DEBUG let store = StoreOf(initialState: Feature.State(child: Feature.State())) { @@ -38,6 +38,7 @@ #endif } + @MainActor func testOptionalScope_CachedStore() { #if DEBUG let store = StoreOf(initialState: Feature.State(child: Feature.State())) { @@ -49,6 +50,7 @@ #endif } + @MainActor func testOptionalScope_StoreIfLet() { #if DEBUG let store = StoreOf(initialState: Feature.State(child: Feature.State())) { @@ -65,6 +67,7 @@ } @available(*, deprecated) + @MainActor func testOptionalScope_StoreIfLet_UncachedStore() { #if DEBUG let store = StoreOf(initialState: Feature.State(child: Feature.State())) { @@ -98,6 +101,7 @@ #endif } + @MainActor func testIdentifiedArrayScope_CachedStore() { #if DEBUG let store = StoreOf(initialState: Feature.State(rows: [Feature.State()])) { @@ -113,6 +117,7 @@ } @available(*, deprecated) + @MainActor func testIdentifiedArrayScope_UncachedStore() { #if DEBUG let store = StoreOf(initialState: Feature.State(rows: [Feature.State()])) { diff --git a/Tests/ComposableArchitectureTests/ScopeTests.swift b/Tests/ComposableArchitectureTests/ScopeTests.swift index a12c6ee82ddd..f392b35738fb 100644 --- a/Tests/ComposableArchitectureTests/ScopeTests.swift +++ b/Tests/ComposableArchitectureTests/ScopeTests.swift @@ -2,9 +2,9 @@ import ComposableArchitecture import XCTest - @MainActor @available(*, deprecated, message: "TODO: Update to use case pathable syntax with Swift 5.9") final class ScopeTests: BaseTCATestCase { + @MainActor func testStructChild() async { let store = TestStore(initialState: Feature.State()) { Feature() @@ -24,6 +24,7 @@ } } + @MainActor func testEnumChild() async { let store = TestStore(initialState: Feature.State()) { Feature() @@ -41,6 +42,7 @@ } #if DEBUG + @MainActor func testNilChild() async { let store = TestStoreOf(initialState: Child2.State.count(0)) { Scope(state: \.name, action: \.name) {} diff --git a/Tests/ComposableArchitectureTests/StoreFilterTests.swift b/Tests/ComposableArchitectureTests/StoreFilterTests.swift index 4f5465591a5e..5781116a6cc3 100644 --- a/Tests/ComposableArchitectureTests/StoreFilterTests.swift +++ b/Tests/ComposableArchitectureTests/StoreFilterTests.swift @@ -2,11 +2,11 @@ import Combine @_spi(Internals) import ComposableArchitecture import XCTest -@MainActor final class StoreInvalidationTests: BaseTCATestCase { - var cancellables: Set = [] - + @MainActor func testInvalidation() { + var cancellables: Set = [] + let store = Store(initialState: nil) {} .scope( id: nil, @@ -18,7 +18,7 @@ final class StoreInvalidationTests: BaseTCATestCase { var count = 0 viewStore.publisher .sink { _ in count += 1 } - .store(in: &self.cancellables) + .store(in: &cancellables) XCTAssertEqual(count, 1) viewStore.send(()) diff --git a/Tests/ComposableArchitectureTests/StoreLifetimeTests.swift b/Tests/ComposableArchitectureTests/StoreLifetimeTests.swift index 85ddedc29de5..a4835b222901 100644 --- a/Tests/ComposableArchitectureTests/StoreLifetimeTests.swift +++ b/Tests/ComposableArchitectureTests/StoreLifetimeTests.swift @@ -3,9 +3,9 @@ @_spi(Logging) import ComposableArchitecture import XCTest - @MainActor final class StoreLifetimeTests: BaseTCATestCase { @available(*, deprecated) + @MainActor func testStoreCaching() { let grandparentStore = Store(initialState: Grandparent.State()) { Grandparent() @@ -23,6 +23,7 @@ } @available(*, deprecated) + @MainActor func testStoreInvalidation() { let grandparentStore = Store(initialState: Grandparent.State()) { Grandparent() @@ -50,6 +51,7 @@ } #if DEBUG + @MainActor func testStoreDeinit() { Logger.shared.isEnabled = true do { @@ -66,6 +68,7 @@ ) } + @MainActor func testStoreDeinit_RunningEffect() async { XCTTODO( "We would like for this to pass, but it requires full deprecation of uncached child stores" @@ -95,6 +98,7 @@ await self.fulfillment(of: [effectFinished], timeout: 0.5) } + @MainActor func testStoreDeinit_RunningCombineEffect() async { XCTTODO( "We would like for this to pass, but it requires full deprecation of uncached child stores" diff --git a/Tests/ComposableArchitectureTests/StorePerceptionTests.swift b/Tests/ComposableArchitectureTests/StorePerceptionTests.swift index e31273d190ca..1100c66abcb0 100644 --- a/Tests/ComposableArchitectureTests/StorePerceptionTests.swift +++ b/Tests/ComposableArchitectureTests/StorePerceptionTests.swift @@ -4,8 +4,8 @@ import XCTest @available(iOS 16, macOS 13, tvOS 16, watchOS 9, *) - @MainActor final class StorePerceptionTests: BaseTCATestCase { + @MainActor func testPerceptionCheck_SkipWhenOutsideView() { let store = Store(initialState: Feature.State()) { Feature() @@ -13,6 +13,7 @@ store.send(.tap) } + @MainActor func testPerceptionCheck_SkipWhenActionClosureOfView() { struct FeatureView: View { let store = Store(initialState: Feature.State()) { @@ -27,6 +28,7 @@ } #if DEBUG + @MainActor func testPerceptionCheck_AccessStateWithoutTracking() { if #unavailable(iOS 17, macOS 14, tvOS 17, watchOS 10) { struct FeatureView: View { @@ -49,6 +51,7 @@ } #endif + @MainActor func testPerceptionCheck_AccessStateWithTracking() { struct FeatureView: View { let store = Store(initialState: Feature.State()) { @@ -63,6 +66,7 @@ render(FeatureView()) } + @MainActor private func render(_ view: some View) { let image = ImageRenderer(content: view).cgImage _ = image diff --git a/Tests/ComposableArchitectureTests/StoreTests.swift b/Tests/ComposableArchitectureTests/StoreTests.swift index 00beb9067998..45cd3ba75b1f 100644 --- a/Tests/ComposableArchitectureTests/StoreTests.swift +++ b/Tests/ComposableArchitectureTests/StoreTests.swift @@ -3,10 +3,10 @@ @_spi(Internals) import ComposableArchitecture import XCTest - @MainActor final class StoreTests: BaseTCATestCase { var cancellables: Set = [] + @MainActor func testCancellableIsRemovedOnImmediatelyCompletingEffect() { let store = Store(initialState: ()) {} @@ -17,6 +17,7 @@ XCTAssertEqual(store.rootStore.effectCancellables.count, 0) } + @MainActor func testCancellableIsRemovedWhenEffectCompletes() { let mainQueue = DispatchQueue.test @@ -47,6 +48,7 @@ } @available(*, deprecated) + @MainActor func testScopedStoreReceivesUpdatesFromParent() { let counterReducer = Reduce({ state, _ in state += 1 @@ -71,6 +73,7 @@ } @available(*, deprecated) + @MainActor func testParentStoreReceivesUpdatesFromChild() { let counterReducer = Reduce({ state, _ in state += 1 @@ -95,6 +98,7 @@ } @available(*, deprecated) + @MainActor func testScopeCallCount_OneLevel_NoSubscription() { var numCalls1 = 0 let store = Store(initialState: 0) {} @@ -112,6 +116,7 @@ } @available(*, deprecated) + @MainActor func testScopeCallCount_OneLevel_Subscribing() { var numCalls1 = 0 let store = Store(initialState: 0) {} @@ -130,6 +135,7 @@ } @available(*, deprecated) + @MainActor func testScopeCallCount_TwoLevels_Subscribing() { var numCalls1 = 0 var numCalls2 = 0 @@ -158,6 +164,7 @@ } @available(*, deprecated) + @MainActor func testScopeCallCount_ThreeLevels_ViewStoreSubscribing() { var numCalls1 = 0 var numCalls2 = 0 @@ -233,6 +240,7 @@ } func testSynchronousEffectsSentAfterSinking() { + @MainActor enum Action { case tap case next1 @@ -279,6 +287,7 @@ XCTAssertEqual(values, [1, 2, 3, 4]) } + @MainActor func testLotsOfSynchronousActions() { enum Action { case incr, noop } let reducer = Reduce({ state, action in @@ -348,6 +357,7 @@ XCTAssertEqual(outputs, [nil, 1, nil, 1, nil, 1, nil]) } + @MainActor func testIfLetTwo() { let parentStore = Store(initialState: 0) { Reduce { state, action in @@ -380,6 +390,7 @@ .store(in: &self.cancellables) } + @MainActor func testActionQueuing() async { let subject = PassthroughSubject() @@ -418,6 +429,7 @@ subject.send(completion: .finished) } + @MainActor func testCoalesceSynchronousActions() { let store = Store(initialState: 0) { Reduce { state, action in @@ -449,6 +461,7 @@ } @available(*, deprecated) + @MainActor func testBufferedActionProcessing() { struct ChildState: Equatable { var count: Int? @@ -510,6 +523,7 @@ ]) } + @MainActor func testCascadingTaskCancellation() async { enum Action { case task, response, response1, response2 } let store = TestStore(initialState: 0) { @@ -540,6 +554,7 @@ await task.cancel() } + @MainActor func testTaskCancellationEmpty() async { enum Action { case task } @@ -556,6 +571,7 @@ } @available(*, deprecated) + @MainActor func testScopeCancellation() async throws { let neverEndingTask = Task { try await Task.never() } @@ -593,6 +609,7 @@ } } } + @MainActor func testOverrideDependenciesDirectlyOnReducer() { let store = Store(initialState: 0) { Feature_testOverrideDependenciesDirectlyOnReducer() @@ -615,6 +632,7 @@ } } } + @MainActor func testOverrideDependenciesDirectlyOnStore() { @Dependency(\.uuid) var uuid let store = Store(initialState: uuid()) { @@ -669,6 +687,7 @@ } } } + @MainActor func testStoreVsTestStore() async { let testStore = TestStore(initialState: Feature_testStoreVsTestStore.State()) { Feature_testStoreVsTestStore() @@ -729,6 +748,7 @@ } } } + @MainActor func testStoreVsTestStore_Publisher() async { let testStore = TestStore(initialState: Feature_testStoreVsTestStore_Publisher.State()) { Feature_testStoreVsTestStore_Publisher() @@ -798,6 +818,7 @@ } } } + @MainActor func testChildParentEffectCancellation() async throws { let mainQueue = DispatchQueue.test let store = Store( @@ -826,6 +847,7 @@ XCTAssertEqual(viewStore.count, 1) } + @MainActor func testInit_InitialState_WithDependencies() async { struct Feature: Reducer { struct State: Equatable { @@ -850,6 +872,7 @@ XCTAssertEqual(store.withState(\.date), Date(timeIntervalSinceReferenceDate: 1_234_567_890)) } + @MainActor func testInit_ReducerBuilder_WithDependencies() async { struct Feature: Reducer { let date: Date @@ -901,6 +924,7 @@ } @available(*, deprecated) + @MainActor func testPresentationScope() async { let store = Store( initialState: Feature_testPresentationScope.State( diff --git a/Tests/ComposableArchitectureTests/TestStoreFailureTests.swift b/Tests/ComposableArchitectureTests/TestStoreFailureTests.swift index deac1da7f71d..adc5c7099036 100644 --- a/Tests/ComposableArchitectureTests/TestStoreFailureTests.swift +++ b/Tests/ComposableArchitectureTests/TestStoreFailureTests.swift @@ -1,8 +1,8 @@ import ComposableArchitecture import XCTest -@MainActor final class TestStoreFailureTests: BaseTCATestCase { + @MainActor func testNoStateChangeFailure() async { enum Action { case first, second } let store = TestStore(initialState: 0) { @@ -35,6 +35,7 @@ final class TestStoreFailureTests: BaseTCATestCase { await store.receive(.second) { _ = $0 } } + @MainActor func testStateChangeFailure() async { struct State: Equatable { var count = 0 } let store = TestStore(initialState: State()) { @@ -57,6 +58,7 @@ final class TestStoreFailureTests: BaseTCATestCase { await store.send(()) { $0.count = 0 } } + @MainActor func testUnexpectedStateChangeOnSendFailure() async { struct State: Equatable { var count = 0 } let store = TestStore(initialState: State()) { @@ -79,6 +81,7 @@ final class TestStoreFailureTests: BaseTCATestCase { await store.send(()) } + @MainActor func testUnexpectedStateChangeOnReceiveFailure() async { struct State: Equatable { var count = 0 } enum Action { case first, second } @@ -107,6 +110,7 @@ final class TestStoreFailureTests: BaseTCATestCase { await store.receive(.second) } + @MainActor func testReceivedActionAfterDeinit() async { enum Action { case first, second } let store = TestStore(initialState: 0) { @@ -129,6 +133,7 @@ final class TestStoreFailureTests: BaseTCATestCase { await store.send(.first) } + @MainActor func testEffectInFlightAfterDeinit() async { let store = TestStore(initialState: 0) { Reduce { state, action in @@ -162,6 +167,7 @@ final class TestStoreFailureTests: BaseTCATestCase { await store.send(()) } + @MainActor func testSendActionBeforeReceivingFailure() async { enum Action { case first, second } let store = TestStore(initialState: 0) { @@ -190,6 +196,7 @@ final class TestStoreFailureTests: BaseTCATestCase { await store.receive(.second) } + @MainActor func testReceiveNonExistentActionFailure() async { enum Action { case action } let store = TestStore(initialState: 0) { @@ -206,6 +213,7 @@ final class TestStoreFailureTests: BaseTCATestCase { await store.receive(.action) } + @MainActor func testReceiveUnexpectedActionFailure() async { enum Action { case first, second } let store = TestStore(initialState: 0) { @@ -235,6 +243,7 @@ final class TestStoreFailureTests: BaseTCATestCase { await store.receive(.first) } + @MainActor func testModifyClosureThrowsErrorFailure() async { let store = TestStore(initialState: 0) { Reduce { _, _ in .none } @@ -249,6 +258,7 @@ final class TestStoreFailureTests: BaseTCATestCase { } } + @MainActor func testExpectedStateEqualityMustModify() async { let store = TestStore(initialState: 0) { Reduce { state, action in diff --git a/Tests/ComposableArchitectureTests/TestStoreNonExhaustiveTests.swift b/Tests/ComposableArchitectureTests/TestStoreNonExhaustiveTests.swift index a8ce40e48e8f..82d91973a5c0 100644 --- a/Tests/ComposableArchitectureTests/TestStoreNonExhaustiveTests.swift +++ b/Tests/ComposableArchitectureTests/TestStoreNonExhaustiveTests.swift @@ -2,8 +2,8 @@ import ComposableArchitecture import XCTest - @MainActor final class TestStoreNonExhaustiveTests: BaseTCATestCase { + @MainActor func testSkipReceivedActions_NonStrict() async { let store = TestStore(initialState: 0) { Reduce { state, action in @@ -23,6 +23,7 @@ XCTAssertEqual(store.state, 2) } + @MainActor func testSkipReceivedActions_Strict() async { let store = TestStore(initialState: 0) { Reduce { state, action in @@ -46,6 +47,7 @@ await store.skipReceivedActions(strict: true) } + @MainActor func testSkipReceivedActions_NonExhaustive() async { let store = TestStore(initialState: 0) { Reduce { state, action in @@ -66,6 +68,7 @@ XCTAssertEqual(store.state, 2) } + @MainActor func testSkipReceivedActions_PartialExhaustive() async { let store = TestStore(initialState: 0) { Reduce { state, action in @@ -86,6 +89,7 @@ XCTAssertEqual(store.state, 2) } + @MainActor func testCancelInFlightEffects_NonStrict() async { let store = TestStore(initialState: 0) { Reduce { _, action in @@ -97,6 +101,7 @@ await store.skipInFlightEffects(strict: false) } + @MainActor func testCancelInFlightEffects_Strict() async { let store = TestStore(initialState: 0) { Reduce { _, action in @@ -112,6 +117,7 @@ await store.skipInFlightEffects(strict: true) } + @MainActor func testCancelInFlightEffects_NonExhaustive() async { let store = TestStore(initialState: 0) { Reduce { _, action in @@ -124,6 +130,7 @@ await store.skipInFlightEffects(strict: false) } + @MainActor func testCancelInFlightEffects_PartialExhaustive() async { let store = TestStore(initialState: 0) { Reduce { _, action in @@ -137,6 +144,7 @@ } // Confirms that you don't have to receive all actions before the test completes. + @MainActor func testIgnoreReceiveActions_PartialExhaustive() async { let store = TestStore(initialState: 0) { Reduce { _, action in @@ -149,6 +157,7 @@ } // Confirms that you don't have to receive all actions before the test completes. + @MainActor func testIgnoreReceiveActions_NonExhaustive() async { let store = TestStore(initialState: 0) { Reduce { _, action in @@ -161,6 +170,7 @@ } // Confirms that all effects do not need to complete before the test completes. + @MainActor func testIgnoreInFlightEffects_PartialExhaustive() async { let store = TestStore(initialState: 0) { Reduce { _, action in @@ -173,6 +183,7 @@ } // Confirms that all effects do not need to complete before the test completes. + @MainActor func testIgnoreInFlightEffects_NonExhaustive() async { let store = TestStore(initialState: 0) { Reduce { _, action in @@ -185,6 +196,7 @@ } // Confirms that you don't have to assert on all state changes in a non-exhaustive test store. + @MainActor func testNonExhaustiveSend_PartialExhaustive() async { let store = TestStore(initialState: Counter.State()) { Counter() @@ -205,6 +217,7 @@ } } + @MainActor func testNonExhaustiveSend_PartialExhaustive_Prefix() async { let store = TestStore(initialState: Counter.State()) { Counter() @@ -219,6 +232,7 @@ // Confirms that you don't have to assert on all state changes in a non-exhaustive test store, // *but* if you make an incorrect mutation you will still get a failure. + @MainActor func testNonExhaustiveSend_PartialExhaustive_BadAssertion() async { let store = TestStore(initialState: Counter.State()) { Counter() @@ -245,6 +259,7 @@ // Confirms that you don't have to assert on all state changes in a non-exhaustive test store, // *and* that informational boxes of what was not asserted on is not shown. + @MainActor func testNonExhaustiveSend_NonExhaustive() async { let store = TestStore(initialState: Counter.State()) { Counter() @@ -259,6 +274,7 @@ // Confirms that you can send actions without having received all effect actions in // non-exhaustive test stores. + @MainActor func testSend_SkipReceivedActions() async { struct State: Equatable { var count = 0 @@ -298,6 +314,7 @@ // Confirms that if you receive an action in a non-exhaustive test store with a bad assertion // you will still get a failure. + @MainActor func testSend_SkipReceivedActions_BadAssertion() async { struct State: Equatable { var count = 0 @@ -345,6 +362,7 @@ // Confirms that with non-exhaustive test stores you can send multiple actions without asserting // on any state changes until the very last action. + @MainActor func testMultipleSendsWithAssertionOnLast() async { let store = TestStore(initialState: Counter.State()) { Counter() @@ -365,6 +383,7 @@ // Confirms that you don't have to assert on all state changes when receiving an action from an // effect in a non-exhaustive test store. + @MainActor func testReceive_StateChange() async { let store = TestStore(initialState: NonExhaustiveReceive.State()) { NonExhaustiveReceive() @@ -388,6 +407,7 @@ } // Confirms that you can skip receiving certain effect actions in a non-exhaustive test store. + @MainActor func testReceive_SkipAction() async { let store = TestStore(initialState: NonExhaustiveReceive.State()) { NonExhaustiveReceive() @@ -408,6 +428,7 @@ // Confirms that you are allowed to send actions without having received all actions queued // from effects. + @MainActor func testSendWithUnreceivedAction() async { let store = TestStore(initialState: NonExhaustiveReceive.State()) { NonExhaustiveReceive() @@ -425,6 +446,7 @@ // Confirms that when you send an action the test store skips any unreceived actions // automatically. + @MainActor func testSendWithUnreceivedActions_SkipsActions() async { enum Action: Equatable { case tap @@ -455,6 +477,7 @@ XCTAssertEqual(store.state, 86) } + @MainActor func testPartialExhaustivityPrefix() async { let testScheduler = DispatchQueue.test enum Action { @@ -495,6 +518,7 @@ // Ignore in-flight effect } + @MainActor func testCasePathReceive_PartialExhaustive() async { let store = TestStore(initialState: NonExhaustiveReceive.State()) { NonExhaustiveReceive() @@ -510,6 +534,7 @@ } } + @MainActor func testCasePathReceive_NonExhaustive() async { let store = TestStore(initialState: NonExhaustiveReceive.State()) { NonExhaustiveReceive() @@ -525,6 +550,7 @@ } } + @MainActor func testCasePathReceive_Exhaustive() async { let store = TestStore(initialState: NonExhaustiveReceive.State()) { NonExhaustiveReceive() @@ -541,6 +567,7 @@ } } + @MainActor func testCasePathReceive_Exhaustive_NonEquatable() async { let store = TestStore(initialState: 0) { Reduce { state, action in @@ -557,6 +584,7 @@ await store.receive(\.response) } + @MainActor func testPredicateReceive_Exhaustive_NonEquatable() async { struct NonEquatable {} enum Action { @@ -579,6 +607,7 @@ await store.receive { if case .response = $0 { return true } else { return false } } } + @MainActor func testCasePathReceive_SkipReceivedAction() async { let store = TestStore(initialState: NonExhaustiveReceive.State()) { NonExhaustiveReceive() @@ -591,6 +620,7 @@ } } + @MainActor func testCasePathReceive_WrongAction() async { let store = TestStore(initialState: NonExhaustiveReceive.State()) { NonExhaustiveReceive() @@ -610,6 +640,7 @@ await store.receive(\.response2) } + @MainActor func testCasePathReceive_ReceivedExtraAction() async { let store = TestStore(initialState: NonExhaustiveReceive.State()) { NonExhaustiveReceive() @@ -628,6 +659,7 @@ await store.receive(\.response2) } + @MainActor func testXCTModifyExhaustive() async { struct State: Equatable { var child: Int? = 0 @@ -669,6 +701,7 @@ } } + @MainActor func testXCTModifyNonExhaustive() async { enum Action { case tap, response } let store = TestStore(initialState: Optional(1)) { @@ -691,6 +724,7 @@ } } + @MainActor func testReceiveNonExhaustiveWithTimeout() async { struct State: Equatable {} enum Action: Equatable { case tap, response1, response2 } @@ -716,6 +750,7 @@ await store.receive(.response2, timeout: 1_000_000_000) } + @MainActor func testReceiveNonExhaustiveWithTimeoutMultipleNonMatching() async { struct State: Equatable {} enum Action: Equatable { case tap, response1, response2 } @@ -751,6 +786,7 @@ await store.receive(.response2, timeout: 1_000_000_000) } + @MainActor func testReceiveNonExhaustiveWithTimeoutMultipleMatching() async { struct State: Equatable {} enum Action: Equatable { case tap, response1, response2 } @@ -776,6 +812,7 @@ await store.receive(.response2, timeout: 1_000_000_000) } + @MainActor func testNonExhaustive_ShowSkippedAssertions_ExpectedStateToChange() async { let store = TestStore(initialState: 0) { Reduce { _, _ in .none } @@ -787,6 +824,7 @@ // This example comes from Krzysztof Zabłocki's blog post: // https://www.merowing.info/exhaustive-testing-in-tca/ + @MainActor func testKrzysztofExample1() async { let store = TestStore(initialState: KrzysztofExample.State()) { KrzysztofExample() @@ -800,6 +838,7 @@ // This example comes from Krzysztof Zabłocki's blog post: // https://www.merowing.info/exhaustive-testing-in-tca/ + @MainActor func testKrzysztofExample2() async { let store = TestStore(initialState: KrzysztofExample.State()) { KrzysztofExample() @@ -816,6 +855,7 @@ // This example comes from Krzysztof Zabłocki's blog post: // https://www.merowing.info/exhaustive-testing-in-tca/ + @MainActor func testKrzysztofExample3() async { let mainQueue = DispatchQueue.test @@ -834,6 +874,7 @@ XCTAssertEqual(store.state.age, 34) } + @MainActor func testEffectfulAssertion_NonExhaustiveTestStore_ShowSkippedAssertions() async { struct Model: Equatable { let id: UUID diff --git a/Tests/ComposableArchitectureTests/TestStoreTests.swift b/Tests/ComposableArchitectureTests/TestStoreTests.swift index 6b3c0f53a4e5..336c6cc82627 100644 --- a/Tests/ComposableArchitectureTests/TestStoreTests.swift +++ b/Tests/ComposableArchitectureTests/TestStoreTests.swift @@ -3,8 +3,8 @@ import ComposableArchitecture import XCTest - @MainActor final class TestStoreTests: BaseTCATestCase { + @MainActor func testEffectConcatenation() async { struct State: Equatable {} @@ -53,6 +53,7 @@ await store.send(.d) } + @MainActor func testAsync() async { enum Action: Equatable { case tap @@ -76,6 +77,7 @@ } } + @MainActor func testExpectedStateEquality() async { struct State: Equatable { var count: Int = 0 @@ -123,6 +125,7 @@ } } + @MainActor func testExpectedStateEqualityMustModify() async { struct State: Equatable { var count: Int = 0 @@ -157,6 +160,7 @@ } } + @MainActor func testReceiveActionMatchingPredicate() async { enum Action: Equatable { case noop, finished @@ -191,6 +195,7 @@ await store.receive { $0 == .noop } } + @MainActor func testStateAccess() async { enum Action { case a, b, c, d } let store = TestStore(initialState: 0) { @@ -246,6 +251,7 @@ } } } + @MainActor func testOverrideDependenciesDirectlyOnReducer() async { let store = TestStore(initialState: 0) { Feature_testOverrideDependenciesDirectlyOnReducer() @@ -276,6 +282,7 @@ } } } + @MainActor func testOverrideDependenciesOnTestStore() async { let store = TestStore(initialState: 0) { Feature_testOverrideDependenciesOnTestStore() @@ -299,6 +306,7 @@ } } } + @MainActor func testOverrideDependenciesOnTestStore_MidwayChange() async { let store = TestStore(initialState: 0) { Feature_testOverrideDependenciesOnTestStore_MidwayChange() @@ -333,6 +341,7 @@ } } } + @MainActor func testOverrideDependenciesOnTestStore_Init() async { let store = TestStore(initialState: 0) { Feature_testOverrideDependenciesOnTestStore_Init() @@ -376,6 +385,7 @@ } } } + @MainActor func testDependenciesEarlyBinding() async { let store = TestStore(initialState: Feature_testDependenciesEarlyBinding.State()) { Feature_testDependenciesEarlyBinding() @@ -395,6 +405,7 @@ } } + @MainActor func testPrepareDependenciesCalledOnce() { var count = 0 let store = TestStore(initialState: 0) { @@ -407,6 +418,7 @@ _ = store } + @MainActor func testEffectEmitAfterSkipInFlightEffects() async { let mainQueue = DispatchQueue.test enum Action: Equatable { case tap, response } @@ -433,6 +445,7 @@ } } + @MainActor func testAssert_NonExhaustiveTestStore() async { let store = TestStore(initialState: 0) { EmptyReducer() @@ -444,6 +457,7 @@ } } + @MainActor func testAssert_NonExhaustiveTestStore_Failure() async { let store = TestStore(initialState: 0) { EmptyReducer() @@ -466,6 +480,7 @@ } } + @MainActor func testSubscribeReceiveCombineScheduler() async { let subject = PassthroughSubject() let scheduler = DispatchQueue.test @@ -504,6 +519,7 @@ await task.cancel() } + @MainActor func testMainSerialExecutor_AutoAssignsAndResets_False() async { uncheckedUseMainSerialExecutor = false XCTAssertFalse(uncheckedUseMainSerialExecutor) @@ -516,6 +532,7 @@ _ = store } + @MainActor func testMainSerialExecutor_AutoAssignsAndResets_True() async { uncheckedUseMainSerialExecutor = true XCTAssertTrue(uncheckedUseMainSerialExecutor) @@ -528,6 +545,7 @@ _ = store } + @MainActor func testReceiveCaseKeyPathWithValue() async { let store = TestStore(initialState: 0) { Reduce { state, action in @@ -561,6 +579,7 @@ await store.receive(\.delegate.success, 43) } + @MainActor func testSendCaseKeyPath() async { let store = TestStore(initialState: 0) { Reduce { state, action in @@ -598,6 +617,7 @@ await store.receive(\.delegate.success, 42) } + @MainActor func testBindingTestStore_WhenStateAndActionHaveSameName() async { let store = TestStore(initialState: .init()) { SameNameForStateAndAction() diff --git a/Tests/ComposableArchitectureTests/ThrottleTests.swift b/Tests/ComposableArchitectureTests/ThrottleTests.swift index ac59f67ef7e4..707e0d44be14 100644 --- a/Tests/ComposableArchitectureTests/ThrottleTests.swift +++ b/Tests/ComposableArchitectureTests/ThrottleTests.swift @@ -3,10 +3,10 @@ import ComposableArchitecture import XCTest - @MainActor final class EffectThrottleTests: BaseTCATestCase { let mainQueue = DispatchQueue.test + @MainActor func testThrottleLatest_Publisher() async { let store = TestStore(initialState: ThrottleFeature.State()) { ThrottleFeature(id: #function, latest: true) @@ -46,6 +46,7 @@ } } + @MainActor func testThrottleLatest_Async() async { let store = TestStore(initialState: ThrottleFeature.State()) { ThrottleFeature(id: #function, latest: true) @@ -85,6 +86,7 @@ } } + @MainActor func testThrottleFirst_Publisher() async { let store = TestStore(initialState: ThrottleFeature.State()) { ThrottleFeature(id: #function, latest: false) @@ -124,6 +126,7 @@ } } + @MainActor func testThrottleAfterInterval_Publisher() async { let store = TestStore(initialState: ThrottleFeature.State()) { ThrottleFeature(id: #function, latest: true) @@ -145,6 +148,7 @@ } } + @MainActor func testThrottleEmitsFirstValueOnce_Publisher() async { let store = TestStore(initialState: ThrottleFeature.State()) { ThrottleFeature(id: #function, latest: true) diff --git a/Tests/ComposableArchitectureTests/ViewStoreTests.swift b/Tests/ComposableArchitectureTests/ViewStoreTests.swift index 39315804c2fc..15a6dd3d0d0b 100644 --- a/Tests/ComposableArchitectureTests/ViewStoreTests.swift +++ b/Tests/ComposableArchitectureTests/ViewStoreTests.swift @@ -2,16 +2,17 @@ import Combine import ComposableArchitecture import XCTest -@MainActor final class ViewStoreTests: BaseTCATestCase { var cancellables: Set = [] + @MainActor override func setUpWithError() throws { try super.setUpWithError() equalityChecks = 0 subEqualityChecks = 0 } + @MainActor func testPublisherFirehose() { let store = Store(initialState: 0) {} let viewStore = ViewStore(store, observe: { $0 }) @@ -31,6 +32,7 @@ final class ViewStoreTests: BaseTCATestCase { } @available(*, deprecated) + @MainActor func testEqualityChecks() { let store = Store(initialState: State()) {} @@ -69,6 +71,7 @@ final class ViewStoreTests: BaseTCATestCase { XCTAssertEqual(16, subEqualityChecks) } + @MainActor func testAccessViewStoreStateInPublisherSink() { let reducer = Reduce { count, _ in count += 1 @@ -91,6 +94,7 @@ final class ViewStoreTests: BaseTCATestCase { XCTAssertEqual([0, 1, 2, 3], results) } + @MainActor func testWillSet() { let reducer = Reduce { count, _ in count += 1 @@ -115,6 +119,7 @@ final class ViewStoreTests: BaseTCATestCase { XCTAssertEqual([0, 1, 2], results) } + @MainActor func testPublisherOwnsViewStore() { let reducer = Reduce { count, _ in count += 1 @@ -132,6 +137,7 @@ final class ViewStoreTests: BaseTCATestCase { XCTAssertEqual(results, [0, 1]) } + @MainActor func testStorePublisherSubscriptionOrder() { let store = Store(initialState: 0) { Reduce { state, _ in @@ -176,6 +182,7 @@ final class ViewStoreTests: BaseTCATestCase { XCTAssertEqual(results, Array(repeating: [0, 1, 2], count: 10).flatMap { $0 }) } + @MainActor func testSendWhile() async { enum Action { case response @@ -200,6 +207,7 @@ final class ViewStoreTests: BaseTCATestCase { XCTAssertEqual(viewStore.state, false) } + @MainActor func testSuspend() { let expectation = self.expectation(description: "await") Task { @@ -231,6 +239,7 @@ final class ViewStoreTests: BaseTCATestCase { self.wait(for: [expectation], timeout: 1) } + @MainActor func testAsyncSend() async throws { enum Action { case tap @@ -257,6 +266,7 @@ final class ViewStoreTests: BaseTCATestCase { XCTAssertEqual(viewStore.state, 42) } + @MainActor func testAsyncSendCancellation() async throws { enum Action { case tap