diff --git a/GliaWidgets/Sources/ViewController/Survey/Components/SingleChoiceQuestionView/Survey.SingleChoiceQuestionView.swift b/GliaWidgets/Sources/ViewController/Survey/Components/SingleChoiceQuestionView/Survey.SingleChoiceQuestionView.swift index 79225afce..aac938310 100644 --- a/GliaWidgets/Sources/ViewController/Survey/Components/SingleChoiceQuestionView/Survey.SingleChoiceQuestionView.swift +++ b/GliaWidgets/Sources/ViewController/Survey/Components/SingleChoiceQuestionView/Survey.SingleChoiceQuestionView.swift @@ -85,9 +85,12 @@ extension Survey { zip(props.options, optionsStack.arrangedSubviews) .forEach { opt, view in guard let checkboxView = view as? CheckboxView else { return } + + let state = Self.handleSelection(with: props, option: opt) + checkboxView.props = .init( title: opt.name, - state: props.selected == opt ? .selected : .active + state: state ) { opt.select(opt) } @@ -95,6 +98,22 @@ extension Survey { validationError.isHidden = !props.showValidationError } + static func handleSelection( + with props: Props, + option opt: Survey.Option + ) -> CheckboxView.State { + // If user selected or it should be selected by default. + let isSelected = props.selected == opt || props.defaultOption == opt + + // Trigger selection manually because the option has + // been selected by default, not because of user input. + if isSelected, props.selected == nil { + opt.select(opt) + } + + return isSelected ? .selected : .active + } + // MARK: - Private private let style: Theme.SurveyStyle.SingleQuestion @@ -109,6 +128,7 @@ extension Survey.SingleChoiceQuestionView { var showValidationError: Bool var options: [Survey.Option] var selected: Survey.Option? + var defaultOption: Survey.Option? var answerContainer: CoreSdkClient.SurveyAnswerContainer? let accessibility: Accessibility @@ -124,6 +144,7 @@ extension Survey.SingleChoiceQuestionView { showValidationError: Bool = false, options: [Survey.Option] = [], selected: Survey.Option? = nil, + defaultOption: Survey.Option? = nil, answerContainer: CoreSdkClient.SurveyAnswerContainer? = nil, accessibility: Accessibility ) { @@ -133,6 +154,7 @@ extension Survey.SingleChoiceQuestionView { self.showValidationError = showValidationError self.options = options self.selected = selected + self.defaultOption = defaultOption self.answerContainer = answerContainer self.accessibility = accessibility } diff --git a/GliaWidgets/Sources/ViewController/Survey/Mocks/Survey.ViewController.Props.Mock.swift b/GliaWidgets/Sources/ViewController/Survey/Mocks/Survey.ViewController.Props.Mock.swift index f28070a4c..e63ffbb74 100644 --- a/GliaWidgets/Sources/ViewController/Survey/Mocks/Survey.ViewController.Props.Mock.swift +++ b/GliaWidgets/Sources/ViewController/Survey/Mocks/Survey.ViewController.Props.Mock.swift @@ -16,6 +16,23 @@ extension Survey.ViewController.Props { ) } + static func emptyPropsMockWithDefaultValue() -> Survey.ViewController.Props { + return Survey.ViewController.Props( + header: "Survey title", + props: [ + makeScalePropsMock(), + makeInputPropsMock(), + makeBooleanPropsMock(), + makeSinglePropsMock(defaultOption: .init( + name: "Second option", + value: "\(2)" + )) + ], + submit: { _ in }, + cancel: {} + ) + } + static func filledPropsMock() -> Survey.ViewController.Props { return Survey.ViewController.Props( header: "Survey title", @@ -99,6 +116,7 @@ private extension Survey.ViewController.Props { static func makeSinglePropsMock( selectedOption: Survey.Option? = nil, + defaultOption: Survey.Option? = nil, showValidationError: Bool = false ) -> Survey.SingleChoiceQuestionView.Props { var props = Survey.SingleChoiceQuestionView.Props( @@ -113,6 +131,7 @@ private extension Survey.ViewController.Props { .init(name: "Second option", value: "\(2)"), .init(name: "Third option", value: "\(3)") ].compactMap { $0 } + props.defaultOption = defaultOption props.selected = selectedOption return props } diff --git a/GliaWidgets/Sources/ViewController/Survey/Survey.ViewController.Props.swift b/GliaWidgets/Sources/ViewController/Survey/Survey.ViewController.Props.swift index eeb986ba3..0b75dacf0 100644 --- a/GliaWidgets/Sources/ViewController/Survey/Survey.ViewController.Props.swift +++ b/GliaWidgets/Sources/ViewController/Survey/Survey.ViewController.Props.swift @@ -203,10 +203,24 @@ extension Survey.ViewController.Props { ? Localization.Survey.Question.Required.Accessibility.label : nil + let defaultOption: Survey.Option? = { + let defaultOption = sdkQuestion.options?.first { + $0.isDefault == true + } + + guard let defaultOption else { return nil } + + return .init( + name: defaultOption.label, + value: defaultOption.id.rawValue + ) + }() + var scaleProps = Survey.SingleChoiceQuestionView.Props( id: sdkQuestion.id.rawValue, title: sdkQuestion.text, isRequired: sdkQuestion.required, + defaultOption: defaultOption, accessibility: .init(value: accessibilityValue) ) let handleSingleOptionSelection = { (option: Survey.Option) in diff --git a/GliaWidgetsTests/Sources/Survey.SingleChouceQuestionViewTests.swift b/GliaWidgetsTests/Sources/Survey.SingleChouceQuestionViewTests.swift new file mode 100644 index 000000000..3a277f00b --- /dev/null +++ b/GliaWidgetsTests/Sources/Survey.SingleChouceQuestionViewTests.swift @@ -0,0 +1,92 @@ +import Foundation +import XCTest +@testable import GliaWidgets + +final class SurveySingleChoiceQuestionViewTests: XCTestCase { + static let firstOption = Survey.Option(name: "Option 1", value: "1") + static let secondOption = Survey.Option(name: "Option 2", value: "2") + + var props: Survey.SingleChoiceQuestionView.Props = { + var props = Survey.SingleChoiceQuestionView.Props( + id: "1", + title: "Survey", + isRequired: true, + accessibility: .init(value: "") + ) + props.options = [ + firstOption, + secondOption + ] + return props + }() + + func test_regularOptionIsActive() { + let regularOption = Self.firstOption + + let selection = Survey.SingleChoiceQuestionView.handleSelection( + with: props, + option: regularOption + ) + + XCTAssertEqual(selection, .active) + } + + func test_defaultOptionIsSelected() { + var hasSelectedDefaultOption = false + + let defaultOption = Survey.Option( + name: "Option 1", + value: "1", + select: { _ in + hasSelectedDefaultOption = true + } + ) + + props.defaultOption = defaultOption + props.options = [defaultOption, Self.secondOption] + + let selection = Survey.SingleChoiceQuestionView.handleSelection( + with: props, + option: defaultOption + ) + + XCTAssertEqual(selection, .selected) + XCTAssertEqual(hasSelectedDefaultOption, true) + } + + func test_regularOptionIsActiveWhenDefaultIsPresent() { + let defaultOption = Self.firstOption + props.defaultOption = defaultOption + + let selection = Survey.SingleChoiceQuestionView.handleSelection( + with: props, + option: Self.secondOption + ) + + XCTAssertEqual(selection, .active) + } + + func test_selectedOptionIsSelected() { + let selectedOption = Self.firstOption + props.selected = selectedOption + + let selection = Survey.SingleChoiceQuestionView.handleSelection( + with: props, + option: selectedOption + ) + + XCTAssertEqual(selection, .selected) + } + + func test_regularOptionIsActiveWhenSelectedIsPresent() { + let selectedOption = Self.firstOption + props.selected = selectedOption + + let selection = Survey.SingleChoiceQuestionView.handleSelection( + with: props, + option: Self.secondOption + ) + + XCTAssertEqual(selection, .active) + } +} diff --git a/SnapshotTests/SurveyViewControllerVoiceOverTests.swift b/SnapshotTests/SurveyViewControllerVoiceOverTests.swift index 1a41f6403..c82f891e7 100644 --- a/SnapshotTests/SurveyViewControllerVoiceOverTests.swift +++ b/SnapshotTests/SurveyViewControllerVoiceOverTests.swift @@ -13,6 +13,15 @@ final class SurveyViewControllerVoiceOverTests: SnapshotTestCase { viewController.assertSnapshot(as: .accessibilityImage) } + func test_emptySurveyWithDefaultValue() { + let viewController = Survey.ViewController( + viewFactory: .mock(), + environment: .init(notificationCenter: .mock), + props: .emptyPropsMockWithDefaultValue() + ) + viewController.assertSnapshot(as: .accessibilityImage) + } + func test_filledSurvey() { let viewController = Survey.ViewController( viewFactory: .mock(),