callOnChange Throws Errors
I am having issue using callOnChange. It always throws "MyView does not have 'onChange' modifier". I have tried calling it on the main view (sut) and its embedded NavigationView (on which onChangeOf is actually called). What I am missing? 🤔
Hey,
I just tried calling onChange for the following test view:
struct MyView: View, Inspectable {
let val = "initial"
var body: some View {
NavigationView {
Text("Hello")
}.onChange(of: val) { value in
}
}
}
and test:
func testOnChange() throws {
guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
else { throw XCTSkip() }
let sut = try MyView().inspect().navigationView()
try sut.callOnChange(newValue: "123")
}
It does not throw the error. Try running it on your end, compare MyView to the view you have and let me know the essential difference.
Thanks for the quick reply. Your code works fine. Mine doesn't. I have been trying to debug it and change your code to fail and I think I managed to break it. Here is the code after the modification:
The model:
class ScoreObject: NSObject, ObservableObject {
@Published var score: String? = "10"
}
class UserProgress: NSObject, ObservableObject {
@Published var scoreObject: ScoreObject = ScoreObject()
}
The view and its test:
struct MyView: View, Inspectable {
@ObservedObject fileprivate var val = UserProgress()
var body: some View {
NavigationView {
Text("Hello")
}.onChange(of: self.val.scoreObject.score) { value in
}
}
}
func testOnChange() throws {
let sut = try MyView().inspect().navigationView()
try sut.callOnChange(newValue: "20")
}
If you run this test, it will fail with this error: caught error: "NavigationView<Text> does not have 'onChange' modifier". The difference here is that the object I am observing is an optional. If I removed the ?, the test will succeed.
This is the same as my issue. Mine is a property of an NSManagedObject. The best practice for such objects to have them all optional. It breaks the tests, though. I can look for a workaround, but it would be nice if callOnChange could detect that and save me more lines of test code.
The other solution is to have onChangeOf get called by itself. By that I mean detecting the change during the test run and call its perform block without the need to callOnChange.
Found the bug and fixed it. Thank you for reporting!
Until the fix is published, a workaround is to explicitly wrap the parameter in Optional. That is, instead of
try sut.callOnChange(newValue: "123")
use
try sut.callOnChange(newValue: Optional("123"))
Released with v0.9.2