-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Closed
Description
Description
I have the following struct, which is shared in memory:
struct Journal: Equatable {}
extension PersistenceReaderKey where Self == PersistenceKeyDefault<InMemoryKey<Journal?>> {
static var journal: Self {
return PersistenceKeyDefault(.inMemory("journal"), nil)
}
}I then have a feature that can show two other features, one of which contains the shared journal:
@Reducer
struct EntryFeature {
@ObservableState
struct State: Equatable {
var url: URL
@SharedReader(.journal) var journal
}
}
@Reducer
struct DayFeature {
@ObservableState
struct State: Equatable {
var entries: [EntryFeature.State]
}
}And the feature that shows them:
@Reducer
struct CalendarFeature {
@Reducer(state: .equatable)
enum Destination {
case day(DayFeature)
case entry(EntryFeature)
}
@ObservableState
struct State: Equatable {
@Presents
var destination: Destination.State?
@Shared(.journal) var journal
}
enum Action: Equatable {
case destination(PresentationAction<Destination.Action>)
case loadEntry(URL)
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .loadEntry(let url):
let updatedEntryState = EntryFeature.State(url: url)
state.destination = .entry(updatedEntryState)
return .none
case .destination:
return .none
}
}
.ifLet(\.$destination, action: \.destination)
}
}
extension CalendarFeature.Destination.Action: Equatable {}Now when trying to test this setup then the test passes when run on its own but fails when run together with another, independent test, that
a) shows the same destination as will be set in the brittle test and
b) sets the shared journal to nil.
This happens even when the test are run in .serialized mode.
@Suite(.serialized)
@MainActor
struct Test_CalendarFeature {
let journal = Journal()
@Test
func settingSharedVariableNil() async {
// We never use this store but if we remove it, the issue doesn't appear
let _ = TestStore(
initialState: .init(
// This has to be the same entry that will be set by the other test. You can try to change it to .entryFeature2 and everything passes
destination: .day(.init(entries: [.entryFeature1]))
)
) {
CalendarFeature()
}
@Shared(.journal) var sharedJournal
$sharedJournal.withLock {
$0 = nil
}
// We can but don't even need to send an action here
}
// This test passes when it's run alone but fails when it's run as part of the suite together with the other test, even when both tests are serialized
@Test
func brittleTest() async {
@Shared(.journal) var sharedJournal
$sharedJournal.withLock {
$0 = journal
}
let store = TestStore(
initialState: .init()
) {
CalendarFeature()
}
await store.send(.loadEntry(.entry1)) {
$0.destination = .entry(.entryFeature1)
}
}
}
// MARK: - Test Items
extension URL {
static let entry1 = URL(fileURLWithPath: "/some/path/")
static let entry2 = URL(fileURLWithPath: "/some/other/path/")
}
extension EntryFeature.State {
static let entryFeature1 = EntryFeature.State(
url: .entry1
)
static let entryFeature2 = EntryFeature.State(
url: .entry2
)
}Checklist
- I have determined whether this bug is also reproducible in a vanilla SwiftUI project.
- If possible, I've reproduced the issue using the
mainbranch of this package. - This issue hasn't been addressed in an existing GitHub issue or discussion.
Expected behavior
The test yields the same result whether run independently or as part of a suite.
Actual behavior
Test passes when run independently but not when run as part of a test suite.
Reproducing project
https://github.com/dominikmayer/TCA-Shared-Test-Issue/
The Composable Architecture version information
1.15.2
Destination operating system
macOS 15.0
Xcode version information
Version 16.0 (16A242d)
Swift Compiler version information
swift-driver version: 1.115 Apple Swift version 6.0 (swiftlang-6.0.0.9.10 clang-1600.0.26.2)
Target: arm64-apple-macosx15.0vander2675
Metadata
Metadata
Assignees
Labels
No labels