149 lines
5.0 KiB
Swift
149 lines
5.0 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import bookstax
|
|
|
|
// MARK: - Mock
|
|
|
|
final class MockShareAPIService: ShareAPIServiceProtocol, @unchecked Sendable {
|
|
|
|
var shelvesToReturn: [ShelfSummary] = []
|
|
var booksToReturn: [BookSummary] = []
|
|
var chaptersToReturn: [ChapterSummary] = []
|
|
var errorToThrow: Error?
|
|
|
|
func fetchShelves() async throws -> [ShelfSummary] {
|
|
if let error = errorToThrow { throw error }
|
|
return shelvesToReturn
|
|
}
|
|
|
|
func fetchBooks(shelfId: Int) async throws -> [BookSummary] {
|
|
if let error = errorToThrow { throw error }
|
|
return booksToReturn
|
|
}
|
|
|
|
func fetchChapters(bookId: Int) async throws -> [ChapterSummary] {
|
|
if let error = errorToThrow { throw error }
|
|
return chaptersToReturn
|
|
}
|
|
|
|
func createPage(bookId: Int, chapterId: Int?, title: String, markdown: String) async throws -> PageResult {
|
|
if let error = errorToThrow { throw error }
|
|
return PageResult(id: 42, name: title)
|
|
}
|
|
}
|
|
|
|
// MARK: - Tests
|
|
|
|
@Suite("ShareViewModel")
|
|
@MainActor
|
|
struct ShareViewModelTests {
|
|
|
|
private func makeDefaults() -> UserDefaults {
|
|
let name = "test.bookstax.shareext.\(UUID().uuidString)"
|
|
let defaults = UserDefaults(suiteName: name)!
|
|
defaults.removePersistentDomain(forName: name)
|
|
return defaults
|
|
}
|
|
|
|
// MARK: 1. Shelves are loaded on start
|
|
|
|
@Test("Beim Start werden alle Regale geladen")
|
|
func shelvesLoadOnStart() async throws {
|
|
let mock = MockShareAPIService()
|
|
mock.shelvesToReturn = [
|
|
ShelfSummary(id: 1, name: "Regal A", slug: "a"),
|
|
ShelfSummary(id: 2, name: "Regal B", slug: "b")
|
|
]
|
|
let vm = ShareViewModel(sharedText: "Testinhalt",
|
|
apiService: mock,
|
|
defaults: makeDefaults())
|
|
await vm.loadShelves()
|
|
|
|
#expect(vm.shelves.count == 2)
|
|
#expect(vm.shelves[0].name == "Regal A")
|
|
#expect(vm.isLoading == false)
|
|
#expect(vm.errorMessage == nil)
|
|
}
|
|
|
|
// MARK: 2. Selecting a shelf loads its books
|
|
|
|
@Test("Shelf-Auswahl lädt Bücher nach")
|
|
func selectingShelfLoadsBooksAsync() async throws {
|
|
let mock = MockShareAPIService()
|
|
mock.booksToReturn = [
|
|
BookSummary(id: 100, name: "Buch 1", slug: "b1"),
|
|
BookSummary(id: 101, name: "Buch 2", slug: "b2")
|
|
]
|
|
let vm = ShareViewModel(sharedText: "Test",
|
|
apiService: mock,
|
|
defaults: makeDefaults())
|
|
|
|
await vm.selectShelf(ShelfSummary(id: 10, name: "Regal X", slug: "x"))
|
|
|
|
#expect(vm.selectedShelf?.id == 10)
|
|
#expect(vm.books.count == 2)
|
|
#expect(vm.isLoading == false)
|
|
}
|
|
|
|
// MARK: 3. Last shelf/book is restored from UserDefaults
|
|
|
|
@Test("Gespeicherte Shelf- und Book-IDs werden beim Start wiederhergestellt")
|
|
func lastSelectionIsRestored() async throws {
|
|
let mock = MockShareAPIService()
|
|
mock.shelvesToReturn = [ShelfSummary(id: 5, name: "Gespeichertes Regal", slug: "saved")]
|
|
mock.booksToReturn = [BookSummary(id: 50, name: "Gespeichertes Buch", slug: "saved-b")]
|
|
|
|
let defaults = makeDefaults()
|
|
defaults.set(5, forKey: "shareExtension.lastShelfID")
|
|
defaults.set(50, forKey: "shareExtension.lastBookID")
|
|
|
|
let vm = ShareViewModel(sharedText: "Test",
|
|
apiService: mock,
|
|
defaults: defaults)
|
|
await vm.loadShelves()
|
|
|
|
#expect(vm.selectedShelf?.id == 5, "Letztes Regal soll wiederhergestellt sein")
|
|
#expect(vm.selectedBook?.id == 50, "Letztes Buch soll wiederhergestellt sein")
|
|
}
|
|
|
|
// MARK: 4. Title auto-populated from first line
|
|
|
|
@Test("Seitentitel wird aus erster Zeile des Textes befüllt")
|
|
func titleAutoPopulatedFromFirstLine() {
|
|
let vm = ShareViewModel(sharedText: "Erste Zeile\nZweite Zeile",
|
|
apiService: MockShareAPIService())
|
|
#expect(vm.pageTitle == "Erste Zeile")
|
|
}
|
|
|
|
// MARK: 5. Save page sets isSaved
|
|
|
|
@Test("Seite speichern setzt isSaved auf true")
|
|
func savePageSetsisSaved() async throws {
|
|
let mock = MockShareAPIService()
|
|
let vm = ShareViewModel(sharedText: "Inhalt", apiService: mock)
|
|
vm.pageTitle = "Mein Titel"
|
|
vm.selectedBook = BookSummary(id: 1, name: "Buch", slug: "buch")
|
|
|
|
await vm.savePage()
|
|
|
|
#expect(vm.isSaved == true)
|
|
#expect(vm.errorMessage == nil)
|
|
}
|
|
|
|
// MARK: 6. isSaveDisabled logic
|
|
|
|
@Test("Speichern ist deaktiviert ohne Titel oder Buch")
|
|
func isSaveDisabledWithoutTitleOrBook() {
|
|
let vm = ShareViewModel(sharedText: "Test", apiService: MockShareAPIService())
|
|
|
|
vm.pageTitle = ""
|
|
#expect(vm.isSaveDisabled == true)
|
|
|
|
vm.pageTitle = "Titel"
|
|
#expect(vm.isSaveDisabled == true) // no book yet
|
|
|
|
vm.selectedBook = BookSummary(id: 1, name: "Buch", slug: "b")
|
|
#expect(vm.isSaveDisabled == false)
|
|
}
|
|
}
|