mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 02:29:55 +02:00
Confirming a transfer/history deletion flashed the same confirmation alert a second time before it went away. The destructive button runs confirmDelete synchronously (setting isDeleting = true), while the alert's isPresented dismiss binding fires asynchronously and then no-ops because its `if !isDeleting` guard is already false — leaving the open flag set, so macOS re-reads the binding as true and re-presents the alert until the async delete finally clears it. Close the confirmation flag synchronously in confirmDeleteTransfer / confirmHistoryDelete so there's no window for re-presentation. Tests assert the flag clears immediately, before the async delete completes.
71 lines
2.6 KiB
Swift
71 lines
2.6 KiB
Swift
import XCTest
|
|
@testable import VniDrop
|
|
|
|
/// Ports the receive-side state-machine assertions from `feature/ViewModelsTest.kt`.
|
|
@MainActor
|
|
final class ReceiveModelTests: XCTestCase {
|
|
|
|
private func makeModel(_ core: FakeCoreGateway) -> ReceiveModel {
|
|
ReceiveModel(
|
|
repository: core,
|
|
fileSystemService: FakeFileSystemService(),
|
|
preferences: Fixtures.preferences(),
|
|
messages: UiMessageController()
|
|
)
|
|
}
|
|
|
|
func testDeleteHistoryItemDeletesTerminalReceiveTransfer() async {
|
|
let core = FakeCoreGateway()
|
|
let model = makeModel(core)
|
|
core.setState(CoreState(isInitialized: true, transfers: [Fixtures.transfer(id: 5, direction: .receive, status: .done)]))
|
|
await waitUntil { model.coreState.transfers.contains { $0.transferId == 5 } }
|
|
|
|
model.requestDeleteHistoryItem(5)
|
|
XCTAssertEqual(model.state.historyDeleteTarget, .transfer(transferId: 5))
|
|
|
|
model.confirmHistoryDelete()
|
|
// Must close immediately (not after the async delete) so the alert can't
|
|
// re-present on macOS.
|
|
XCTAssertNil(model.state.historyDeleteTarget)
|
|
await waitUntil { core.deletedTransfers.contains(5) }
|
|
XCTAssertEqual(core.deletedTransfers, [5])
|
|
XCTAssertNil(model.state.historyDeleteTarget)
|
|
}
|
|
|
|
func testClearHistoryCallsClearReceiveHistory() async {
|
|
let core = FakeCoreGateway()
|
|
let model = makeModel(core)
|
|
core.setState(CoreState(isInitialized: true, transfers: [Fixtures.transfer(id: 5, direction: .receive, status: .done)]))
|
|
await waitUntil { !model.coreState.transfers.isEmpty }
|
|
|
|
model.requestClearHistory()
|
|
XCTAssertEqual(model.state.historyDeleteTarget, .all)
|
|
|
|
model.confirmHistoryDelete()
|
|
await waitUntil { core.clearReceiveHistoryCount == 1 }
|
|
XCTAssertEqual(core.clearReceiveHistoryCount, 1)
|
|
XCTAssertNil(model.state.historyDeleteTarget)
|
|
}
|
|
|
|
func testDeleteHistoryItemIgnoresNonTerminalTransfer() async {
|
|
let core = FakeCoreGateway()
|
|
let model = makeModel(core)
|
|
core.setState(CoreState(isInitialized: true, transfers: [Fixtures.transfer(id: 9, direction: .receive, status: .receiving)]))
|
|
await waitUntil { !model.coreState.transfers.isEmpty }
|
|
|
|
model.requestDeleteHistoryItem(9)
|
|
XCTAssertNil(model.state.historyDeleteTarget) // in-flight receive can't be deleted from history
|
|
}
|
|
|
|
func testCancelActiveReceiveCancelsTheReceivingTransfer() async {
|
|
let core = FakeCoreGateway()
|
|
let model = makeModel(core)
|
|
core.setState(CoreState(isInitialized: true, transfers: [Fixtures.transfer(id: 7, direction: .receive, status: .receiving)]))
|
|
await waitUntil { !model.coreState.transfers.isEmpty }
|
|
|
|
model.cancelActiveReceive()
|
|
await waitUntil { core.cancelledTransfers.contains(7) }
|
|
XCTAssertEqual(core.cancelledTransfers, [7])
|
|
}
|
|
}
|