Files
attendi/Packages/Features/Tests/Recording/RecordingViewModelTests.swift
T

271 lines
6.9 KiB
Swift

import SwiftUI
import Testing
@testable import Recording
@Suite("Recording view model")
struct RecordingViewModelTests {
typealias Model = RecordingView.Model
// MARK: Initial state
@MainActor
@Suite("Initial state")
struct InitialState {
@Test func `initial state is not recording with a zeroed timer`() {
let model = Model()
#expect(model.state == .notRecording)
#expect(model.secondsElapsed == 0)
#expect(model.timerText == "00:00")
}
}
// MARK: Button presses
@MainActor
@Suite("Button presses")
struct ButtonPresses {
@Test(arguments: zip(
[Model.State.notRecording, .recording, .paused, .processing],
[Model.State.recording, .paused, .recording, .processing]
))
func `pressed main transitions to the expected state`(
from initial: Model.State,
to expected: Model.State
) {
let model = Model()
model.state = initial
model.pressedMain()
#expect(model.state == expected)
}
@Test(arguments: zip(
[Model.State.notRecording, .recording, .paused, .processing],
[Model.State.notRecording, .recording, .processing, .processing]
))
func `pressed send transitions to the expected state`(
from initial: Model.State,
to expected: Model.State
) {
let model = Model()
model.state = initial
model.pressedSend()
#expect(model.state == expected)
}
}
// MARK: Computed properties
@MainActor
@Suite("Computed properties")
struct ComputedProperties {
@Test(arguments: zip(
[Model.State.notRecording, .recording, .paused, .processing],
[ImageResource.Icon.record, .Icon.pause, .Icon.record, .Icon.record]
))
func `main icon matches the state`(
for state: Model.State,
expected: ImageResource
) {
let model = Model()
model.state = state
#expect(model.iconMain == expected)
}
@Test(arguments: zip(
[Model.State.notRecording, .recording, .paused, .processing],
[nil, nil, ImageResource.Icon.send, nil]
))
func `send icon matches the state`(
for state: Model.State,
expected: ImageResource?
) {
let model = Model()
model.state = state
#expect(model.iconSend == expected)
}
@Test(arguments: zip(
[Model.State.notRecording, .recording, .paused, .processing],
[false, false, false, true]
))
func `is processing only while processing`(
for state: Model.State,
expected: Bool
) {
let model = Model()
model.state = state
#expect(model.isProcessing == expected)
}
@Test(arguments: zip(
[Model.State.notRecording, .recording, .paused, .processing],
[false, false, false, true]
))
func `main button is disabled only while processing`(
for state: Model.State,
expected: Bool
) {
let model = Model()
model.state = state
#expect(model.shouldDisableMain == expected)
}
@Test(arguments: zip(
[Model.State.notRecording, .recording, .paused, .processing],
[false, false, true, true]
))
func `send button is visible while paused or processing`(
for state: Model.State,
expected: Bool
) {
let model = Model()
model.state = state
#expect(model.shouldShowSend == expected)
}
@Test(arguments: zip(
[Model.State.notRecording, .recording, .paused, .processing],
[false, true, true, true]
))
func `timer is visible unless not recording`(
for state: Model.State,
expected: Bool
) {
let model = Model()
model.state = state
#expect(model.shouldShowTimer == expected)
}
}
// MARK: Timer
@MainActor
@Suite("Timer")
struct Timer {
@Test func `ticks while recording`() async throws {
let model = Model()
model.state = .recording
model.updatedState(shouldRestartTimer: true)
try await Task.sleep(for: .seconds(1.2))
#expect(model.secondsElapsed >= 1)
#expect(model.timerText == "00:01")
model.state = .notRecording
model.updatedState(shouldRestartTimer: false)
}
@Test func `stops while paused`() async throws {
let model = Model()
model.state = .recording
model.updatedState(shouldRestartTimer: true)
try await Task.sleep(for: .seconds(1.2))
model.state = .paused
model.updatedState(shouldRestartTimer: false)
let secondsWhenPaused = model.secondsElapsed
try await Task.sleep(for: .seconds(1.2))
#expect(secondsWhenPaused >= 1)
#expect(model.secondsElapsed == secondsWhenPaused)
}
@Test func `keeps elapsed seconds when resumed`() async throws {
let model = Model()
model.state = .recording
model.updatedState(shouldRestartTimer: true)
try await Task.sleep(for: .seconds(1.2))
model.state = .paused
model.updatedState(shouldRestartTimer: false)
let secondsWhenPaused = model.secondsElapsed
model.state = .recording
model.updatedState(shouldRestartTimer: false)
#expect(model.secondsElapsed == secondsWhenPaused)
model.state = .notRecording
model.updatedState(shouldRestartTimer: false)
}
@Test func `restarts for a new recording`() async throws {
let model = Model()
model.state = .recording
model.updatedState(shouldRestartTimer: true)
try await Task.sleep(for: .seconds(1.2))
model.state = .paused
model.updatedState(shouldRestartTimer: false)
model.state = .recording
model.updatedState(shouldRestartTimer: true)
#expect(model.secondsElapsed == 0)
model.state = .notRecording
model.updatedState(shouldRestartTimer: false)
}
}
// MARK: Processing
@MainActor
@Suite("Processing")
struct Processing {
@Test func `returns to not recording`() async throws {
let model = Model()
model.state = .processing
model.updatedState(shouldRestartTimer: false)
try await Task.sleep(for: .seconds(2.5))
#expect(model.state == .notRecording)
}
}
}