mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Cancel message edit if content remains unchanged
This commit is contained in:
committed by
Stefan Ceriu
parent
de13fa5438
commit
5741290471
@@ -19,6 +19,7 @@ final class ComposerToolbarViewModelTests {
|
||||
private var viewModel: ComposerToolbarViewModel!
|
||||
private var completionSuggestionServiceMock: CompletionSuggestionServiceMock!
|
||||
private var draftServiceMock: ComposerDraftServiceMock!
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
init() {
|
||||
setUpViewModel()
|
||||
@@ -546,6 +547,106 @@ final class ComposerToolbarViewModelTests {
|
||||
#expect(viewModel.context.plainComposerText == NSAttributedString(string: "Hello world"))
|
||||
}
|
||||
|
||||
@Test
|
||||
func sendingUnchangedPlainTextEditCancelsTheEdit() {
|
||||
viewModel.context.composerFormattingEnabled = false
|
||||
let mode: ComposerMode = .edit(originalEventOrTransactionID: .eventID("mock"), type: .default)
|
||||
viewModel.process(timelineAction: .setMode(mode: mode))
|
||||
viewModel.process(timelineAction: .setText(plainText: "Hello world!", htmlText: nil))
|
||||
|
||||
let sentMessages = collectSentMessages()
|
||||
viewModel.process(viewAction: .sendMessage)
|
||||
|
||||
#expect(sentMessages.value.isEmpty)
|
||||
#expect(viewModel.state.composerMode == .default)
|
||||
#expect(viewModel.context.plainComposerText.string.isEmpty)
|
||||
}
|
||||
|
||||
@Test
|
||||
func sendingUnchangedRichTextEditCancelsTheEdit() {
|
||||
viewModel.context.composerFormattingEnabled = true
|
||||
let mode: ComposerMode = .edit(originalEventOrTransactionID: .eventID("mock"), type: .default)
|
||||
viewModel.process(timelineAction: .setMode(mode: mode))
|
||||
viewModel.process(timelineAction: .setText(plainText: "Hello **world**!", htmlText: "Hello <strong>world</strong>!"))
|
||||
viewModel.state.composerEmpty = false
|
||||
|
||||
let sentMessages = collectSentMessages()
|
||||
viewModel.process(viewAction: .sendMessage)
|
||||
|
||||
#expect(sentMessages.value.isEmpty)
|
||||
#expect(viewModel.state.composerMode == .default)
|
||||
#expect(wysiwygViewModel.content.markdown.isEmpty)
|
||||
}
|
||||
|
||||
@Test
|
||||
func sendingUnchangedEditRestoresTheVolatileDraft() {
|
||||
viewModel.context.composerFormattingEnabled = false
|
||||
viewModel.context.plainComposerText = .init(string: "Work in progress")
|
||||
let mode: ComposerMode = .edit(originalEventOrTransactionID: .eventID("mock"), type: .default)
|
||||
viewModel.process(timelineAction: .setMode(mode: mode))
|
||||
viewModel.process(timelineAction: .setText(plainText: "Hello world!", htmlText: nil))
|
||||
draftServiceMock.loadVolatileDraftReturnValue = .init(plainText: "Work in progress", htmlText: nil, draftType: .newMessage)
|
||||
|
||||
let sentMessages = collectSentMessages()
|
||||
viewModel.process(viewAction: .sendMessage)
|
||||
|
||||
#expect(sentMessages.value.isEmpty)
|
||||
#expect(viewModel.state.composerMode == .default)
|
||||
#expect(viewModel.context.plainComposerText.string == "Work in progress")
|
||||
#expect(draftServiceMock.clearVolatileDraftCallsCount == 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
func sendingUnchangedCaptionEditCancelsTheEdit() {
|
||||
viewModel.context.composerFormattingEnabled = false
|
||||
let mode: ComposerMode = .edit(originalEventOrTransactionID: .eventID("mock"), type: .editCaption)
|
||||
viewModel.process(timelineAction: .setMode(mode: mode))
|
||||
viewModel.process(timelineAction: .setText(plainText: "A caption", htmlText: nil))
|
||||
|
||||
let sentMessages = collectSentMessages()
|
||||
viewModel.process(viewAction: .sendMessage)
|
||||
|
||||
#expect(sentMessages.value.isEmpty)
|
||||
#expect(viewModel.state.composerMode == .default)
|
||||
}
|
||||
|
||||
@Test
|
||||
func sendingChangedEditSendsTheEdit() async throws {
|
||||
viewModel.context.composerFormattingEnabled = false
|
||||
let mode: ComposerMode = .edit(originalEventOrTransactionID: .eventID("mock"), type: .default)
|
||||
viewModel.process(timelineAction: .setMode(mode: mode))
|
||||
viewModel.process(timelineAction: .setText(plainText: "Hello world!", htmlText: nil))
|
||||
viewModel.context.plainComposerText = .init(string: "Hello world, edited!")
|
||||
|
||||
let deferred = deferFulfillment(viewModel.actions) { action in
|
||||
guard case let .sendMessage(plainText, _, sentMode, _) = action else { return false }
|
||||
return plainText == "Hello world, edited!" && sentMode == mode
|
||||
}
|
||||
viewModel.process(viewAction: .sendMessage)
|
||||
try await deferred.fulfill()
|
||||
}
|
||||
|
||||
@Test
|
||||
func sendingUnchangedEditAfterCancellingAndEditingAgainSendsTheEdit() async throws {
|
||||
// Editing a different message must reset the remembered original content.
|
||||
viewModel.context.composerFormattingEnabled = false
|
||||
viewModel.process(timelineAction: .setMode(mode: .edit(originalEventOrTransactionID: .eventID("first"), type: .default)))
|
||||
viewModel.process(timelineAction: .setText(plainText: "Hello world!", htmlText: nil))
|
||||
viewModel.process(viewAction: .cancelEdit)
|
||||
|
||||
let mode: ComposerMode = .edit(originalEventOrTransactionID: .eventID("second"), type: .default)
|
||||
viewModel.process(timelineAction: .setMode(mode: mode))
|
||||
viewModel.process(timelineAction: .setText(plainText: "Something else", htmlText: nil))
|
||||
viewModel.context.plainComposerText = .init(string: "Hello world!")
|
||||
|
||||
let deferred = deferFulfillment(viewModel.actions) { action in
|
||||
guard case let .sendMessage(plainText, _, sentMode, _) = action else { return false }
|
||||
return plainText == "Hello world!" && sentMode == mode
|
||||
}
|
||||
viewModel.process(viewAction: .sendMessage)
|
||||
try await deferred.fulfill()
|
||||
}
|
||||
|
||||
@Test
|
||||
func restoreVolatileDraftWhenClearing() async {
|
||||
await waitForConfirmation("Volatile draft loaded and cleared", expectedCount: 2) { confirmation in
|
||||
@@ -802,6 +903,18 @@ final class ComposerToolbarViewModelTests {
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private func collectSentMessages() -> CurrentValueSubject<[ComposerToolbarViewModelAction], Never> {
|
||||
let subject = CurrentValueSubject<[ComposerToolbarViewModelAction], Never>([])
|
||||
viewModel.actions
|
||||
.filter { action in
|
||||
guard case .sendMessage = action else { return false }
|
||||
return true
|
||||
}
|
||||
.sink { subject.value.append($0) }
|
||||
.store(in: &cancellables)
|
||||
return subject
|
||||
}
|
||||
|
||||
private func setUpViewModel(initialText: String? = nil, loadDraftClosure: (() async -> Result<ComposerDraftProxy?, ComposerDraftServiceError>)? = nil) {
|
||||
wysiwygViewModel = WysiwygComposerViewModel()
|
||||
completionSuggestionServiceMock = CompletionSuggestionServiceMock(configuration: .init())
|
||||
|
||||
Reference in New Issue
Block a user