-
I have an effect that attempts to download data every 60 seconds public struct Environment {
var backgroundQueue: AnySchedulerOf<DispatchQueue>
var download: () -> AnyPublisher<Data, APIError>
var logError: (Error) -> Effect<Never, Never>
var now: () -> Date
var runLoop: AnySchedulerOf<RunLoop>
var userDefaults: UserDefaults
} case .start:
Effect.timer(id: CancelTimer(), every: .seconds(60), on: environment.runLoop)
.prepend(.init(environment.now()))
.assertNoFailure()
.flatMap(maxPublishers: .max(1), { _ -> Effect<Result<Data, APIError>, Never> in
environment.download()
.handleEvents(receiveOutput: { _ in print("Downloading data") })
.catchToEffect()
})
.map(Action.save)
.eraseToEffect()
.cancellable(id: CancelDownload()) because the download can take some time, I limit the download to 1 in progress with the func test_download_failure_then_success() {
let runLoop = RunLoop.test
var errors: [Error] = []
let store = TestStore(
initialState: Downloader.State(),
reducer: Downloader.reducer,
environment: Downloader.Environment(
backgroundQueue: DispatchQueue.test.eraseToAnyScheduler(),
download: { Fail(error: APIError.invalidBody).eraseToAnyPublisher() },
logError: { error in .fireAndForget { errors.append(error) } },
now: Date.init,
runLoop: runLoop.eraseToAnyScheduler(),
userDefaults: UserDefaults.mock()))
store.assert(
.send(.start),
.receive(.save(.failure(.invalidBody))),
.environment {
$0.download = { Just(Data()).mapError(APIError.unknown).eraseToAnyPublisher() }
},
.do { runLoop.advance(by: .seconds(60)) },
.receive(.save(.success(.init()))),
.send(.cancel)
) The environment.download success is never called. I imagine this has something to do with the maxPublishers, but I cannot figure it out. Any help would be appreciated. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
I think I see what is going on here, and it's tricky. The change you make to the environment to replace the One thing you should be able to do to work around is use a Wanna give that a shot? There's another work around for this but it won't work for you because you specifically need the |
Beta Was this translation helpful? Give feedback.
-
@mbrandonw thanks for the help. Using a |
Beta Was this translation helpful? Give feedback.
I think I see what is going on here, and it's tricky.
The change you make to the environment to replace the
$0.download
endpoint doesn't actually update the environment in theflatMap
. TheflatMap
will capture the environment at the time of sending the.start
action, and will never change after that. In fact, that kinda makes usingenvironment
inside.flatMaps
a little dangerous, in particular when flat mapping from a long living effect like a timer. We should add some documentation/case studies for this behavior.One thing you should be able to do to work around is use a
PassthroughSubject
forenvironment.download
in your test and then send it values to emulate thedownload
effect firing…