Short description of the issue:
When running a test around UISlider, changing the value of the slider does not emit a new signal with the new value.
Expected outcome:
onNext to emit the new value and the test to pass
What actually happens:
onNext does not emit the new value
Self contained code example that reproduces the issue:
let slider = UISlider()
var outValue: Float = 0
slider.rx.value.subscribe(onNext: { value in
outValue = value
}).disposed(by: disposeBag)
slider.value = 0.3
expect(outValue).toEventually(equal(0.3))
RxSwift/RxCocoa/RxBlocking/RxTest version/commit
3.6.1
Platform/Environment
How easy is to reproduce? (chances of successful reproduce after running the self contained code)
Xcode version:
8.3.2
Installation method:
I have multiple versions of Xcode installed:
(so we can know if this is a potential cause of your issue)
Level of RxSwift knowledge:
(this is so we can understand your level of knowledge
and formulate the response in an appropriate manner)
Hi, @jsetting32 ControlProperty does not emit value on programatic changes, only for a user input.
You can force it tho by calling setAction(:, forControlEvents:)
What would setAction(:, forControlEvents:) be invoked by? UISlider? Doesn't look like UISlider has such a method.
Every UIControl has that method.
The point is a Control Event is described as a user initiated action like interacting with the slider or using the keyboard to change a text field.
Programmatically setting the values isn't considered a Control Event in that sense, so that manual invocation is needed
Even though manual invocation hack is possible, don't do it because:
I didn't see setAction(:, forControlEvents:). You meant slider.sendActions(for: UIControlEvents.valueChanged) correct?
Oh, sorry there was a typo, yeah slider.sendActions(for: UIControlEvents.valueChanged)
What would be a good alternative @kzaher? Or just forget the test and assume it works correctly? Was attempting to get a good amount of coverage is why I wanted to manually invoke a control event
@jsetting32
I agree with @kzaher generally speaking.
For example, if the UISlider is driving some PublishSubject in your ViewModel, it would be more proper to test the ViewModel directly and not the UI driving the ViewModel.
In general it makes more sense to test Data and not UI Components.
makes sense @freak4pc 馃憤
Also, I attempted to invoke a user action, but still nothing
let slider = UISlider()
var outValue: Float = 0
slider.rx.value.subscribe(onNext: { value in
outValue = value
}).disposed(by: disposeBag)
slider.value = 0.3
slider.sendActions(for: UIControlEvents.valueChanged)
expect(outValue) == 0.3
expect(outValue).toEventually(equal(0.3))
@jsetting32 As far as I can tell this code snippet works in real app and unit tests. Try putting a breakpoint inside onNext callback.
Again, you shouldn't be using controls inside unit tests unless you are working for Apple and testing UIKit controls.
This isn't a library issue IMHO.
Most helpful comment
Even though manual invocation hack is possible, don't do it because: