:: Add unit tests

This commit is contained in:
Felix Mau
2022-03-10 10:59:37 +01:00
parent 25de79f73d
commit dec430d951
7 changed files with 698 additions and 47 deletions
-34
View File
@@ -1,34 +0,0 @@
//
// ExampleTests.swift
// ExampleTests
//
// Created by Felix Mau on 07.03.22.
//
import XCTest
@testable import Example
class ExampleTests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
// Any test you write for XCTest can be annotated as throws and async.
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
}
func testPerformanceExample() throws {
// This is an example of a performance test case.
measure {
// Put the code you want to measure the time of here.
}
}
}
@@ -0,0 +1,243 @@
//
// GradientActivityIndicatorViewModelTestCase.swift
// ExampleTests
//
// Created by Felix Mau on 26.08.19.
// Copyright © 2019 Felix Mau. All rights reserved.
//
import XCTest
import LightweightObservable
@testable import GradientLoadingBar
// swiftlint:disable:next type_name
final class GradientActivityIndicatorViewModelTestCase: XCTestCase {
// MARK: - Private properties
private var viewModel: GradientActivityIndicatorViewModel!
// MARK: - Public methods
override func setUp() {
super.setUp()
viewModel = GradientActivityIndicatorViewModel()
}
override func tearDown() {
viewModel = nil
super.tearDown()
}
// MARK: - Test initializer
func test_initializer_shouldSetGradientLayerColors_toCorrectValue() {
let expectedGradientLayerColors = makeGradientLayerColors()
XCTAssertEqual(viewModel.gradientLayerColors.value, expectedGradientLayerColors)
}
func test_initializer_shouldSetColorLocationMatrix_toCorrectValue() throws {
let receivedColorLocationMatrix = try XCTUnwrap(viewModel.colorLocationMatrix.value)
let expectedColorLocationMatrix = makeColorLocationMatrix()
// Unfortunately there is no easier way comparing an array of type `NSNumber` / `Double` with a given accuracy.
XCTAssertEqual(receivedColorLocationMatrix.count, expectedColorLocationMatrix.count)
for (receivedColorLocationRow, expectedColorLocationRow) in zip(receivedColorLocationMatrix, expectedColorLocationMatrix) {
XCTAssertEqual(receivedColorLocationRow.count, expectedColorLocationRow.count)
for (receivedColorLocation, expectedColorLocation) in zip(receivedColorLocationRow, expectedColorLocationRow) {
XCTAssertEqual(receivedColorLocation.doubleValue, expectedColorLocation.doubleValue, accuracy: .ulpOfOne)
}
}
}
func test_initializer_shouldSetAnimationDuration_toStaticConfigurationProperty() {
XCTAssertEqual(viewModel.animationDuration.value, TimeInterval.GradientLoadingBar.progressDuration)
}
func test_initializer_shouldSetIsAnimating_toTrue() throws {
XCTAssertTrue(
try XCTUnwrap(viewModel.isAnimating.value)
)
}
func test_initializer_shouldSetGradientColors_toStaticConfigurationProperty() {
XCTAssertEqual(viewModel.gradientColors, UIColor.GradientLoadingBar.gradientColors)
}
func test_initializer_shouldSetProgressAnimationDuration_toStaticConfigurationProperty() {
XCTAssertEqual(viewModel.progressAnimationDuration, TimeInterval.GradientLoadingBar.progressDuration)
}
func test_initializer_ShouldSetIsHidden_toFalse() {
XCTAssertFalse(viewModel.isHidden)
}
// MARK: - Test property `gradientColors`
func test_settingGradientColors_shouldUpdateGradientLayerColorsObservable() {
// Given
let gradientColors: [UIColor] = [.red, .yellow, .green]
// When
viewModel.gradientColors = gradientColors
// Then
//
// `gradientColors = [.red, .yellow, .green]`
// `gradientLayerColors = [.red, .yellow, .green, .yellow, .red, .yellow, .green]`
//
let expectedGradientColors: [UIColor] = [.red, .yellow, .green, .yellow, .red, .yellow, .green]
let expectedGradientLayerColors = expectedGradientColors.map(\.cgColor)
XCTAssertEqual(viewModel.gradientLayerColors.value, expectedGradientLayerColors)
}
func test_settingGradientColors_shouldUpdateColorLocationMatrixObservable() {
// Given
let gradientColors: [UIColor] = [.red, .yellow, .green]
// When
viewModel.gradientColors = gradientColors
// Then
//
// `gradientColors = [.red, .yellow, .green]`
// `gradientLayerColors = [.red, .yellow, .green, .yellow, .red, .yellow, .green]`
//
// i | .red | .yellow | .green | .yellow | .red | .yellow | .green
// 0 | 0 | 0 | 0 | 0 | 0 | 0.5 | 1
// 1 | 0 | 0 | 0 | 0 | 0.5 | 1 | 1
// 2 | 0 | 0 | 0 | 0.5 | 1 | 1 | 1
// 3 | 0 | 0 | 0.5 | 1 | 1 | 1 | 1
// 4 | 0 | 0.5 | 1 | 1 | 1 | 1 | 1
//
let colorLocationMatrix = [
[0, 0, 0, 0, 0, 0.5, 1],
[0, 0, 0, 0, 0.5, 1, 1],
[0, 0, 0, 0.5, 1, 1, 1],
[0, 0, 0.5, 1, 1, 1, 1],
[0, 0.5, 1, 1, 1, 1, 1],
]
let expectedColorLocationMatrix = colorLocationMatrix.map {
$0.map { NSNumber(value: $0) }
}
XCTAssertEqual(viewModel.colorLocationMatrix.value, expectedColorLocationMatrix)
}
// MARK: - Test property `progressAnimationDuration`
func test_settingProgressAnimationDuration_shouldUpdateAnimationDurationObservable() {
// Given
let progressAnimationDuration: TimeInterval = 123
// When
viewModel.progressAnimationDuration = progressAnimationDuration
// Then
XCTAssertEqual(viewModel.animationDuration.value, progressAnimationDuration)
}
// MARK: - Test property `isHidden`
func test_settingIsHiddenToTrue_shouldSetIsAnimatingToFalse() throws {
// When
viewModel.isHidden = true
// Then
XCTAssertFalse(
try XCTUnwrap(viewModel.isAnimating.value)
)
}
func test_settingIsHiddenToFalse_shouldSetIsAnimatingToTrue() throws {
// When
viewModel.isHidden = false
// Then
XCTAssertTrue(
try XCTUnwrap(viewModel.isAnimating.value)
)
}
}
// MARK: - Helpers
extension GradientActivityIndicatorViewModelTestCase {
private func makeGradientLayerColors() -> [CGColor] {
let gradientColors = [
#colorLiteral(red: 0.2980392157, green: 0.8509803922, blue: 0.3921568627, alpha: 1), #colorLiteral(red: 0.3529411765, green: 0.7843137255, blue: 0.9803921569, alpha: 1), #colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1), #colorLiteral(red: 0.2039215686, green: 0.6666666667, blue: 0.862745098, alpha: 1), #colorLiteral(red: 0.3450980392, green: 0.337254902, blue: 0.8392156863, alpha: 1), #colorLiteral(red: 1, green: 0.1764705882, blue: 0.3333333333, alpha: 1),
]
XCTAssertEqual(gradientColors, UIColor.GradientLoadingBar.gradientColors,
"Precondition failed The given gradient colors do not match the current color constant!")
// swiftlint:disable:next identifier_name
let reversedGradientColorsWithoutFirstAndLastValue = [
#colorLiteral(red: 0.3450980392, green: 0.337254902, blue: 0.8392156863, alpha: 1), #colorLiteral(red: 0.2039215686, green: 0.6666666667, blue: 0.862745098, alpha: 1), #colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1), #colorLiteral(red: 0.3529411765, green: 0.7843137255, blue: 0.9803921569, alpha: 1),
]
let infiniteGradientColors = gradientColors + reversedGradientColorsWithoutFirstAndLastValue + gradientColors
return infiniteGradientColors.map(\.cgColor)
}
private func makeColorLocationInitialRow() -> ColorLocationRow {
let gradientLocations = [0, 0.2, 0.4, 0.6, 0.8, 1]
XCTAssertEqual(gradientLocations.count, UIColor.GradientLoadingBar.gradientColors.count,
"Precondition failed The given gradient locations do not match for the current color constant!")
// The current constant has 6 value and therefore we expect 16 gradient layer colors in total.
// Ergo we have to fill the first 10 values with "0", before adding the `gradientLocations`.
//
// .green | .malibu | .azure | .curious | .violet | .red | .violet | .curious | .azure | .malibu | .green | .malibu | .azure | .curious | .violet | .red
// 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0.2 | 0.4 | 0.6 | 0.8 | 1
//
// swiftlint:disable:next identifier_name
let gradientLocationAnimationMatrixInitialRow = Array(repeating: 0.0, count: 10) + gradientLocations
return gradientLocationAnimationMatrixInitialRow.map {
NSNumber(value: $0)
}
}
private func makeColorLocationMatrix() -> ColorLocationMatrix {
let gradientLocations = [0, 0.2, 0.4, 0.6, 0.8, 1]
XCTAssertEqual(gradientLocations.count, UIColor.GradientLoadingBar.gradientColors.count,
"Precondition failed The given gradient locations do not match for the current color constant!")
// The current constant has 6 value and therefore we expect 16 gradient layer colors in total.
// Ergo we have to fill the first 10 values with "0", before adding the `gradientLocations`.
//
// .green | .malibu | .azure | .curious | .violet | .red | .violet | .curious | .azure | .malibu | .green | .malibu | .azure | .curious | .violet | .red
// 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0.2 | 0.4 | 0.6 | 0.8 | 1
// ...
// 0 | 0 | 0 | 0 | 0 | 0 | 0.2 | 0.4 | 0.6 | 0.8 | 1 | 1 | 1 | 1 | 1 | 1
// ...
// 0 | 0.2 | 0.4 | 0.6 | 0.8 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1
//
let colorLocationMatrix = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2, 0.4, 0.6, 0.8, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
]
return colorLocationMatrix.map {
$0.map { NSNumber(value: $0) }
}
}
}
@@ -0,0 +1,125 @@
//
// GradientLoadingBarViewModelTestCase.swift
// ExampleTests
//
// Created by Felix Mau on 26.12.17.
// Copyright © 2017 Felix Mau. All rights reserved.
//
import XCTest
import LightweightObservable
@testable import GradientLoadingBar
final class GradientLoadingBarViewModelTestCase: XCTestCase {
// MARK: - Private properties
private var sharedApplicationMock: SharedApplicationMock!
private var notificationCenter: NotificationCenter!
// MARK: - Public methods
override func setUp() {
super.setUp()
sharedApplicationMock = SharedApplicationMock()
notificationCenter = NotificationCenter()
}
override func tearDown() {
notificationCenter = nil
sharedApplicationMock = nil
super.tearDown()
}
// MARK: - Test observable `superview`
func test_initializer_shouldSetupSuperviewObservable_withNil() throws {
// When
let viewModel = GradientLoadingBarViewModel(sharedApplication: sharedApplicationMock,
notificationCenter: notificationCenter)
// Then
let variable = try XCTUnwrap(viewModel.superview as? Variable, "Cast `Observable` instance to `Variable` in order to validate the initial value.")
XCTAssertNil(variable.value)
}
func test_initializer_shouldSetupSuperviewObservable_withKeyWindow() {
// Given
let keyWindow = KeyWindow()
let passiveWindow = PassiveWindow()
sharedApplicationMock.windows = [keyWindow, passiveWindow]
// When
let viewModel = GradientLoadingBarViewModel(sharedApplication: sharedApplicationMock,
notificationCenter: notificationCenter)
// Then
XCTAssertEqual(viewModel.superview.value, keyWindow)
}
func test_initializer_shouldSetupSuperviewObservable_afterUIWindowDidBecomeKeyNotification() {
// Given
let keyWindow = KeyWindow()
let passiveWindow = PassiveWindow()
sharedApplicationMock.windows = [passiveWindow]
let viewModel = GradientLoadingBarViewModel(sharedApplication: sharedApplicationMock,
notificationCenter: notificationCenter)
// When
sharedApplicationMock.windows.append(keyWindow)
notificationCenter.post(name: UIWindow.didBecomeKeyNotification,
object: nil)
// Then
XCTAssertEqual(viewModel.superview.value, keyWindow)
}
func test_deinit_shouldResetSuperviewObservable_withNil() {
// Given
let keyWindow = KeyWindow()
let passiveWindow = PassiveWindow()
sharedApplicationMock.windows = [keyWindow, passiveWindow]
var viewModel: GradientLoadingBarViewModel? = GradientLoadingBarViewModel(sharedApplication: sharedApplicationMock,
notificationCenter: notificationCenter)
let expectation = expectation(description: "Expected observer to be informed to reset superview to nil.")
var disposeBag = DisposeBag()
// As we've just initialized the view model it has to exist at this point, and therefore we can "safely" use force-unwrapping here.
// swiftlint:disable:next force_unwrapping
viewModel!.superview.subscribe { newSuperview, _ in
guard newSuperview == nil else {
// Skip initial call to observer.
return
}
expectation.fulfill()
}.disposed(by: &disposeBag)
// When
viewModel = nil
// Then
wait(for: [expectation], timeout: 0.1)
}
}
// MARK: - Helpers
private final class KeyWindow: UIWindow {
override var isKeyWindow: Bool { true }
}
private final class PassiveWindow: UIWindow {
override var isKeyWindow: Bool { false }
}
// MARK: - Mocks
private final class SharedApplicationMock: UIApplicationProtocol {
var windows = [UIWindow]()
}
@@ -0,0 +1,76 @@
//
// NotchGradientLoadingBarViewModelTestCase.swift
// ExampleTests
//
// Created by Felix Mau on 26.12.17.
// Copyright © 2017 Felix Mau. All rights reserved.
//
import XCTest
@testable import GradientLoadingBar
final class NotchGradientLoadingBarViewModelTestCase: XCTestCase {
func test_initializer_shouldSetSafeAreaDevice_toIPhoneX() {
// Given
let deviceIdentifiers = ["iPhone10,3", "iPhone10,6", "iPhone11,2", "iPhone11,4", "iPhone11,6", "iPhone11,8"]
deviceIdentifiers.forEach { deviceIdentifier in
// When
let viewModel = NotchGradientLoadingBarViewModel(deviceIdentifier: deviceIdentifier)
// Then
XCTAssertEqual(viewModel.safeAreaDevice, .iPhoneX)
}
}
func test_initializer_shouldSetSafeAreaDevice_toIPhone11() {
// Given
let deviceIdentifiers = ["iPhone12,1", "iPhone12,3", "iPhone12,5"]
deviceIdentifiers.forEach { deviceIdentifier in
// When
let viewModel = NotchGradientLoadingBarViewModel(deviceIdentifier: deviceIdentifier)
// Then
XCTAssertEqual(viewModel.safeAreaDevice, .iPhone11)
}
}
func test_initializer_shouldSetSafeAreaDevice_toIPhone12() {
// Given
let deviceIdentifiers = ["iPhone13,1", "iPhone13,2", "iPhone13,3", "iPhone13,4"]
deviceIdentifiers.forEach { deviceIdentifier in
// When
let viewModel = NotchGradientLoadingBarViewModel(deviceIdentifier: deviceIdentifier)
// Then
XCTAssertEqual(viewModel.safeAreaDevice, .iPhone12)
}
}
func test_initializer_shouldSetSafeAreaDevice_toIPhone13() {
// Given
let deviceIdentifiers = ["iPhone14,4", "iPhone14,5", "iPhone14,2", "iPhone14,3"]
deviceIdentifiers.forEach { deviceIdentifier in
// When
let viewModel = NotchGradientLoadingBarViewModel(deviceIdentifier: deviceIdentifier)
// Then
XCTAssertEqual(viewModel.safeAreaDevice, .iPhone13)
}
}
func test_initializer_shouldSetSafeAreaDevice_toUnknown() {
// Given
let deviceIdentifier = "Foo-Bar-🤡"
// When
let viewModel = NotchGradientLoadingBarViewModel(deviceIdentifier: deviceIdentifier)
// Then
XCTAssertEqual(viewModel.safeAreaDevice, .unknown)
}
}
@@ -0,0 +1,207 @@
//
// GradientActivityIndicatorView+AnimateIsHiddenTestCase.swift
// ExampleTests
//
// Created by Felix Mau on 19.05.19.
// Copyright © 2017 Felix Mau. All rights reserved.
//
import XCTest
@testable import GradientLoadingBar
// swiftlint:disable:next type_name
final class GradientActivityIndicatorViewAnimateIsHiddenTestCase: XCTestCase {
// MARK: - Private properties
private var window: UIWindow!
private var gradientActivityIndicatorView: GradientActivityIndicatorView!
// MARK: - Public methods
override func setUp() {
super.setUp()
// In order for UIView animations to be executed correctly, the corresponding view has to be attached to a visible window.
// Therefore we're gonna use the current key-window, add our testing view here in `setUp()` and remove it later in `tearDown()`.
window = UIApplication.shared.windows.first { $0.isKeyWindow }
gradientActivityIndicatorView = GradientActivityIndicatorView()
window.addSubview(gradientActivityIndicatorView)
}
override func tearDown() {
gradientActivityIndicatorView.removeFromSuperview()
gradientActivityIndicatorView = nil
window = nil
super.tearDown()
}
// MARK: - Test method `animate(isHidden:)`
func test_animateIsHidden_shouldShowView_andCallCompletionHandler() {
// Given
let expectation = expectation(description: "Expect completion handler to be called.")
// Hide view to validate fade-in.
gradientActivityIndicatorView.alpha = 0
gradientActivityIndicatorView.isHidden = true
// When
gradientActivityIndicatorView.animate(isHidden: false, duration: 0.1) { isFinished in
XCTAssertTrue(isFinished)
expectation.fulfill()
}
// Then
wait(for: [expectation], timeout: 1)
XCTAssertFalse(gradientActivityIndicatorView.isHidden)
XCTAssertEqual(gradientActivityIndicatorView.alpha, 1.0, accuracy: CGFloat.ulpOfOne)
}
func test_animateIsHidden_withInterruption_shouldShowView_andCallCompletionHandler() {
// Given
let expectation = expectation(description: "Expect completion handler to be called.")
// Hide view to validate fade-in.
gradientActivityIndicatorView.alpha = 0
gradientActivityIndicatorView.isHidden = true
// When
gradientActivityIndicatorView.animate(isHidden: false, duration: 0.1) { isFinished in
XCTAssertFalse(isFinished)
expectation.fulfill()
}
// Cancel animation.
gradientActivityIndicatorView.layer.removeAllAnimations()
// Then
wait(for: [expectation], timeout: 1)
XCTAssertFalse(gradientActivityIndicatorView.isHidden)
}
func test_animateIsHidden_shouldHideView_andCallCompletionHandler() {
// Given
let expectation = expectation(description: "Expect completion handler to be called.")
// When
gradientActivityIndicatorView.animate(isHidden: true, duration: 0.1) { isFinished in
XCTAssertTrue(isFinished)
expectation.fulfill()
}
// Then
wait(for: [expectation], timeout: 1)
XCTAssertTrue(gradientActivityIndicatorView.isHidden)
XCTAssertEqual(gradientActivityIndicatorView.alpha, 0, accuracy: CGFloat.ulpOfOne)
}
func test_animateIsHidden_withInterruption_shouldNotHideView_andCallCompletionHandler() {
// Given
let expectation = expectation(description: "Expect completion handler to be called.")
// When
gradientActivityIndicatorView.animate(isHidden: true, duration: 0.1) { isFinished in
XCTAssertFalse(isFinished)
expectation.fulfill()
}
// Cancel animation.
gradientActivityIndicatorView.layer.removeAllAnimations()
// Then
wait(for: [expectation], timeout: 1)
XCTAssertFalse(gradientActivityIndicatorView.isHidden, "As we've interrupted the animation, we expect the `isHidden` flag to still be `false`.")
}
// MARK: - Test method `fadeIn()`
func test_fadeIn_shouldShowView_andCallCompletionHandler() {
// Given
let expectation = expectation(description: "Expect completion handler to be called.")
// Hide view to validate fade-in.
gradientActivityIndicatorView.alpha = 0
gradientActivityIndicatorView.isHidden = true
// When
gradientActivityIndicatorView.fadeIn(duration: 0.1) { isFinished in
XCTAssertTrue(isFinished)
expectation.fulfill()
}
// Then
wait(for: [expectation], timeout: 1)
XCTAssertFalse(gradientActivityIndicatorView.isHidden)
XCTAssertEqual(gradientActivityIndicatorView.alpha, 1.0, accuracy: CGFloat.ulpOfOne)
}
func test_fadeIn_withInterruption_shouldShowView_andCallCompletionHandler() {
// Given
let expectation = expectation(description: "Expect completion handler to be called.")
// Hide view to validate fade-in.
gradientActivityIndicatorView.alpha = 0
gradientActivityIndicatorView.isHidden = true
// When
gradientActivityIndicatorView.fadeIn(duration: 0.1) { isFinished in
XCTAssertFalse(isFinished)
expectation.fulfill()
}
// Cancel animation.
gradientActivityIndicatorView.layer.removeAllAnimations()
// Then
wait(for: [expectation], timeout: 1)
XCTAssertFalse(gradientActivityIndicatorView.isHidden)
}
// MARK: - Test method `fadeOut()`
func test_fadeOut_shouldHideView_andCallCompletionHandler() {
// Given
let expectation = expectation(description: "Expect completion handler to be called.")
// When
gradientActivityIndicatorView.fadeOut(duration: 0.1) { isFinished in
XCTAssertTrue(isFinished)
expectation.fulfill()
}
// Then
wait(for: [expectation], timeout: 1)
XCTAssertTrue(gradientActivityIndicatorView.isHidden)
XCTAssertEqual(gradientActivityIndicatorView.alpha, 0, accuracy: CGFloat.ulpOfOne)
}
func test_fadeOut_withInterruption_shouldNotHideView_andCallCompletionHandler() {
// Given
let expectation = expectation(description: "Expect completion handler to be called.")
// When
gradientActivityIndicatorView.fadeOut(duration: 0.1) { isFinished in
XCTAssertFalse(isFinished)
expectation.fulfill()
}
// Cancel animation.
gradientActivityIndicatorView.layer.removeAllAnimations()
// Then
wait(for: [expectation], timeout: 1)
XCTAssertFalse(gradientActivityIndicatorView.isHidden, "As we've interrupted the animation, we expect the `isHidden` flag to still be `false`.")
}
}