RelanceTranscriptionTest.swift
137 lignes · 5738 octets
import XCTest @testable import Card2vcf /// Tests TDD pour la relance de transcription (Lot 3). /// /// Ces tests vérifient que `SyncEngine.relancerTranscriptionInteraction` et /// `relancerTranscriptionNoteProjet` appellent bien l'API, mettent à jour /// le statut local en "en_attente" et effacent l'erreur précédente. final class RelanceTranscriptionTest: XCTestCase { private var db: InMemoryCrmDatabase! private var api: FakeAilianceApi! private var engine: SyncEngine! override func setUp() { super.setUp() db = InMemoryCrmDatabase() api = FakeAilianceApi() engine = SyncEngine(api: api, db: db) } // MARK: - Relance interaction — succès func testRelancerInteraction_appellePApi() async throws { let localId = try await insererInteractionEchec(serverId: "i-rel-1", contactId: "c1") let erreur = try await engine.relancerTranscriptionInteraction(localId: localId) XCTAssertNil(erreur, "Pas d'erreur attendue en cas de succès") XCTAssertEqual(1, api.relancerInteractionCalls.count) XCTAssertEqual("c1", api.relancerInteractionCalls.first?.0) XCTAssertEqual("i-rel-1", api.relancerInteractionCalls.first?.1) } func testRelancerInteraction_repasseStatutEnAttente() async throws { let localId = try await insererInteractionEchec(serverId: "i-rel-2", contactId: "c1") _ = try await engine.relancerTranscriptionInteraction(localId: localId) let updated = try await db.interactionDao.getByLocalId(localId) XCTAssertEqual("en_attente", updated?.transcriptionStatut, "Statut doit repasser à en_attente après relance") } func testRelancerInteraction_effaceErreur() async throws { let localId = try await insererInteractionEchec(serverId: "i-rel-3", contactId: "c1") _ = try await engine.relancerTranscriptionInteraction(localId: localId) let updated = try await db.interactionDao.getByLocalId(localId) XCTAssertNil(updated?.transcriptionErreur, "Motif d'erreur effacé après relance") } // MARK: - Relance interaction — échec réseau func testRelancerInteraction_echecReseau_retourneMsgClair() async throws { let localId = try await insererInteractionEchec(serverId: "i-rel-4", contactId: "c1") api.relancerInteractionResult = .err(code: -1, message: "serveur injoignable") let erreur = try await engine.relancerTranscriptionInteraction(localId: localId) XCTAssertNotNil(erreur, "Message d'erreur attendu") XCTAssertTrue(erreur!.contains("serveur injoignable"), "Message d'erreur clair : \(erreur!)") } func testRelancerInteraction_echecReseau_neModifiePasStatut() async throws { let localId = try await insererInteractionEchec(serverId: "i-rel-5", contactId: "c1") api.relancerInteractionResult = .err(code: -1, message: "réseau") _ = try await engine.relancerTranscriptionInteraction(localId: localId) let kept = try await db.interactionDao.getByLocalId(localId) XCTAssertEqual("echec", kept?.transcriptionStatut, "Statut préservé quand la relance échoue") } // MARK: - Relance note projet — succès func testRelancerNoteProjet_appellePApi() async throws { let localId = try await insererNoteEchec(serverId: "n-rel-1", projetId: "proj-1") let erreur = try await engine.relancerTranscriptionNoteProjet(localId: localId) XCTAssertNil(erreur) XCTAssertEqual(1, api.relancerNoteProjetCalls.count) XCTAssertEqual("proj-1", api.relancerNoteProjetCalls.first?.0) XCTAssertEqual("n-rel-1", api.relancerNoteProjetCalls.first?.1) } func testRelancerNoteProjet_repasseStatutEnAttente() async throws { let localId = try await insererNoteEchec(serverId: "n-rel-2", projetId: "proj-1") _ = try await engine.relancerTranscriptionNoteProjet(localId: localId) let updated = try await db.noteProjetDao.listAll().first { $0.localId == localId } XCTAssertEqual("en_attente", updated?.transcriptionStatut) XCTAssertNil(updated?.transcriptionErreur) } func testRelancerNoteProjet_echecReseau_retourneMsgClair() async throws { let localId = try await insererNoteEchec(serverId: "n-rel-3", projetId: "proj-1") api.relancerNoteProjetResult = .err(code: -1, message: "serveur injoignable") let erreur = try await engine.relancerTranscriptionNoteProjet(localId: localId) XCTAssertNotNil(erreur) XCTAssertTrue(erreur!.contains("serveur injoignable")) } // MARK: - Helpers @discardableResult private func insererInteractionEchec(serverId: String, contactId: String) async throws -> Int64 { var entity = InteractionEntity() entity.serverId = serverId entity.contactServerId = contactId entity.type = "note_vocale" entity.sujet = "Note échouée" entity.transcriptionStatut = "echec" entity.transcriptionErreur = "Erreur Whisper : audio trop court" entity.createdAt = 1_000 return try await db.interactionDao.upsert(entity) } @discardableResult private func insererNoteEchec(serverId: String, projetId: String) async throws -> Int64 { var entity = NoteProjetEntity() entity.serverId = serverId entity.projetServerId = projetId entity.titre = "Note échouée" entity.transcriptionStatut = "echec" entity.transcriptionErreur = "Erreur Whisper : audio trop court" entity.createdAt = 1_000 return try await db.noteProjetDao.upsert(entity) } }
GitRust