I have a SwiftUI view with a view model associated to it.
struct BookmarksView: View {
@StateObject private var viewModel = BookmarksViewModel()
var body: some View {
switch viewModel.viewState {
case .empty:
BookmarksEmptyView()
case .content(let newsLetters):
ListView(newsLetters: newsLetters)
}
}
}
With the PreviewProvider
represented below I'm able to test just the empty
case. Not the content
one.
struct BookmarksView_Previews: PreviewProvider {
static var previews: some View {
BookmarksView()
}
}
Are you able to suggest a way to test BookmarksView
for both cases (i.e. empty
and content
)?
Thanks, Lorenzo
You could create an init so you can inject the view model but use a default value so you don't need to use it normally.
init(viewModel: BookmarksViewModel = BookmarksViewModel() {
_viewModel = StateObject(wrappedValue: viewModel)
}
Now you can create and inject an instance in your preview code
For previews I would add two static properties for creating different versions with different configurations of the view model to be used in the previews. I did this inside a #if DEBUG/#endif
so they can't be used by mistake in a release build.
#if DEBUG
extension BookmarksViewModel {
static let emptyState: BookmarksViewModel = {
BookmarksViewModel(viewState: .empty)
}()
static let contentState: BookmarksViewModel = {
let newsLetters = Newsletter.previews
return BookmarksViewModel(viewState: .content(newsLetters))
}()
}
#endif
Note that since I don't know how the view model is declared I made my own version
This can then be used directly in the previews
struct BookmarksViewEmpty_Previews: PreviewProvider {
static var previews: some View {
BookmarksView(viewModel: .emptyState)
}
}
struct BookmarksViewContent_Previews: PreviewProvider {
static var previews: some View {
BookmarksView(viewModel: .contentState)
}
}
The solution posted by OP is another good way to solve this since the sub-view is now decoupled from the view model which makes it much easier to create previews but there is no need to use @State
properties in a preview since the properties will not change, instead we can create a binding using constant()
struct BookmarksViewEmpty_Previews: PreviewProvider {
static var previews: some View {
BookmarksView(viewState: .constant(.empty))
}
}
struct BookmarksViewContent_Previews: PreviewProvider {
static var previews: some View {
BookmarksView(viewState: .constant(.content(Newsletter.previews)))
}
}