147 lines
6.6 KiB
Swift
147 lines
6.6 KiB
Swift
import Foundation
|
|
import Testing
|
|
import PDFKit
|
|
@testable import GasTankAR
|
|
|
|
@MainActor
|
|
struct LeadDetailDownloadTests {
|
|
private func fixture() async throws -> (DefaultLeadDetailRepository, StubLeadDetailRemoteService, LeadDetail) {
|
|
let service = StubLeadDetailRemoteService(delay: .zero)
|
|
let repository = DefaultLeadDetailRepository(
|
|
remoteService: service,
|
|
cacheDirectory: FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
|
|
)
|
|
let detail = try await repository.detail(id: "L-240318", salesCode: "MKR")
|
|
return (repository, service, detail)
|
|
}
|
|
|
|
@Test
|
|
func metadataDoesNotDownloadPDFsAndProgressMatchesDocuments() async throws {
|
|
let (_, service, detail) = try await fixture()
|
|
#expect(service.downloadCount == 0)
|
|
#expect(detail.offers.count == 3)
|
|
#expect(detail.offers[0].documents.count == 6)
|
|
#expect(detail.offers[0].signedCount == 2)
|
|
#expect(detail.offers[1].documents.count == 5)
|
|
#expect(detail.offers[2].isComplete)
|
|
#expect(detail.photos.count == 10)
|
|
}
|
|
|
|
@Test
|
|
func downloadsActualPDFAndReusesCachedFile() async throws {
|
|
let (repository, service, detail) = try await fixture()
|
|
let document = try #require(detail.offers.first?.documents.first)
|
|
let useCase = DownloadLeadDocumentUseCase(repository: repository)
|
|
let first = try await useCase.execute(document, leadID: detail.lead.id, salesCode: "MKR")
|
|
let pdf = try #require(PDFDocument(url: first))
|
|
#expect(pdf.pageCount == document.pageCount)
|
|
#expect(pdf.string?.contains("Beispieldokument") == true)
|
|
let second = try await useCase.execute(document, leadID: detail.lead.id, salesCode: "MKR")
|
|
#expect(first == second)
|
|
#expect(service.downloadCount == 1)
|
|
try FileManager.default.removeItem(at: first)
|
|
let third = try await useCase.execute(document, leadID: detail.lead.id, salesCode: "MKR")
|
|
#expect(FileManager.default.fileExists(atPath: third.path))
|
|
#expect(service.downloadCount == 2)
|
|
}
|
|
|
|
@Test
|
|
func concurrentDownloadsShareOneRequest() async throws {
|
|
let (repository, service, detail) = try await fixture()
|
|
service.delay = .milliseconds(50)
|
|
let file = try #require(detail.offers.first?.documents.first?.file)
|
|
let first = Task { try await repository.file(file, leadID: detail.lead.id, salesCode: "MKR") }
|
|
let second = Task { try await repository.file(file, leadID: detail.lead.id, salesCode: "MKR") }
|
|
let firstURL = try await first.value
|
|
let secondURL = try await second.value
|
|
#expect(firstURL == secondURL)
|
|
#expect(service.downloadCount == 1)
|
|
}
|
|
|
|
@Test
|
|
func cacheIsScopedToUserAndDocumentVersion() async throws {
|
|
let (repository, service, detail) = try await fixture()
|
|
let file = try #require(detail.offers.first?.documents.first?.file)
|
|
let first = try await repository.file(file, leadID: detail.lead.id, salesCode: "MKR")
|
|
let otherUser = try await repository.file(file, leadID: detail.lead.id, salesCode: "ABC")
|
|
#expect(first != otherUser)
|
|
let nextVersion = LeadFileReference(id: file.id, version: "2", kind: .pdf)
|
|
await #expect(throws: LeadFileError.notFound) {
|
|
try await repository.file(nextVersion, leadID: detail.lead.id, salesCode: "MKR")
|
|
}
|
|
#expect(service.downloadCount == 3)
|
|
}
|
|
|
|
@Test
|
|
func invalidPDFIsNotCachedAndRetrySucceeds() async throws {
|
|
let (repository, service, detail) = try await fixture()
|
|
let file = try #require(detail.offers.first?.documents.first?.file)
|
|
service.fileScenario = .invalidFile
|
|
await #expect(throws: LeadFileError.invalidFile) {
|
|
try await repository.file(file, leadID: detail.lead.id, salesCode: "MKR")
|
|
}
|
|
service.fileScenario = .success
|
|
let url = try await repository.file(file, leadID: detail.lead.id, salesCode: "MKR")
|
|
#expect(PDFDocument(url: url) != nil)
|
|
#expect(service.downloadCount == 2)
|
|
}
|
|
|
|
@Test
|
|
func fileErrorsPreserveLoadedDetailAndMapCorrectly() async throws {
|
|
let (repository, service, detail) = try await fixture()
|
|
let file = try #require(detail.offers.first?.documents.first?.file)
|
|
for (scenario, expected): (StubLeadDetailRemoteService.Scenario, LeadError) in [
|
|
(.offline, .offline), (.timeout, .timeout), (.http(500), .serviceUnavailable),
|
|
(.http(401), .unauthorized), (.http(403), .forbidden)
|
|
] {
|
|
service.fileScenario = scenario
|
|
await #expect(throws: expected) {
|
|
try await repository.file(file, leadID: detail.lead.id, salesCode: "MKR")
|
|
}
|
|
}
|
|
service.fileScenario = .http(404)
|
|
await #expect(throws: LeadFileError.notFound) {
|
|
try await repository.file(file, leadID: detail.lead.id, salesCode: "MKR")
|
|
}
|
|
#expect(detail.lead.id == "L-240318")
|
|
}
|
|
|
|
@Test
|
|
func treeExpandsCollapsesAndKeepsStateWhenSelectingPDF() async throws {
|
|
let (repository, _, _) = try await fixture()
|
|
let model = LeadDetailViewModel(leadID: "L-240318", salesCode: "MKR", repository: repository)
|
|
await model.load()
|
|
let detail = try #require(model.detail)
|
|
#expect(model.expandedOffers == [detail.offers[0].id])
|
|
model.toggleAll()
|
|
#expect(model.isAllExpanded)
|
|
model.selectedDocument = detail.offers[0].documents[0]
|
|
model.selectedDocument = nil
|
|
#expect(model.isAllExpanded)
|
|
model.toggleAll()
|
|
#expect(model.expandedOffers.isEmpty)
|
|
#expect(model.expandedGroups.isEmpty)
|
|
model.toggleOffer(detail.offers[1].id)
|
|
#expect(model.expandedOffers == [detail.offers[1].id])
|
|
}
|
|
|
|
@Test
|
|
func anotherLeadKeepsItsOwnIdentityAndEmptyOffers() async throws {
|
|
let (repository, _, _) = try await fixture()
|
|
let detail = try await repository.detail(id: "L-240326", salesCode: "MKR")
|
|
#expect(detail.lead.companyName == "Schreinerei Vogt")
|
|
#expect(detail.offers.isEmpty)
|
|
#expect(detail.email == nil)
|
|
}
|
|
|
|
@Test
|
|
func photoDownloadProducesAnImage() async throws {
|
|
let (repository, service, detail) = try await fixture()
|
|
let photo = try #require(detail.photos.first)
|
|
let url = try await LoadLeadPhotoUseCase(repository: repository)
|
|
.execute(photo, leadID: detail.lead.id, salesCode: "MKR")
|
|
#expect(FileManager.default.fileExists(atPath: url.path))
|
|
#expect(service.downloadCount == 1)
|
|
}
|
|
}
|