mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Extract composer toolbar to a dedicated component (#1427)
* Extract composer toolbar to a dedicated component * Use publisher for composer mode * Introduce `RoomScreenComposerProvider` * Add `ComposerToolbarViewModelTests` * Rename protocols and add passthrough subjects for focused and composer mode * Remove `ComposerToolbarViewActionHandler` and `ComposerToolbarCoordinatorParameters` * Remove `RoomScreenComposerActionHandlerProtocol` and `RoomScreenComposerProviderProtocol` * Re-arrange code a bit * Remove composer mode being stored on `RoomScreen` * Rename `process(viewAction: ComposerToolbarViewAction)` to `process(composerAction: ComposerToolbarViewAction)` * Replace PassthroughSubject with direct function call * Remove `ComposerToolbarCoordinator` * Remove `cancelEdit` and `cancelReply` from external composer view model actions * Use `RoomScreenComposerAction` as a sub-`RoomScreenViewModelAction` * Move `ComposerToolbarViewModel` callback to actionsSubject * Move `RoomScreenViewModel` callback to actionsSubject * Fix `RoomScreenViewModelTests` * Rename `composerAction` parameter to `roomAction` * Fix unit tests
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
@testable import ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
class ComposerToolbarViewModelTests: XCTestCase {
|
||||
func testComposerFocus() {
|
||||
let viewModel = ComposerToolbarViewModel()
|
||||
viewModel.process(roomAction: .setMode(mode: .edit(originalItemId: TimelineItemIdentifier(timelineID: "mock"))))
|
||||
XCTAssertTrue(viewModel.state.bindings.composerFocused)
|
||||
viewModel.process(roomAction: .removeFocus)
|
||||
XCTAssertFalse(viewModel.state.bindings.composerFocused)
|
||||
}
|
||||
|
||||
func testComposerMode() {
|
||||
let viewModel = ComposerToolbarViewModel()
|
||||
let mode: RoomScreenComposerMode = .edit(originalItemId: TimelineItemIdentifier(timelineID: "mock"))
|
||||
viewModel.process(roomAction: .setMode(mode: mode))
|
||||
XCTAssertEqual(viewModel.state.composerMode, mode)
|
||||
viewModel.process(roomAction: .clear)
|
||||
XCTAssertEqual(viewModel.state.composerMode, .default)
|
||||
}
|
||||
|
||||
func testComposerModeIsPublished() {
|
||||
let viewModel = ComposerToolbarViewModel()
|
||||
let mode: RoomScreenComposerMode = .edit(originalItemId: TimelineItemIdentifier(timelineID: "mock"))
|
||||
let expectation = expectation(description: "Composer mode is published")
|
||||
let cancellable = viewModel
|
||||
.context
|
||||
.$viewState
|
||||
.map(\.composerMode)
|
||||
.removeDuplicates()
|
||||
.dropFirst()
|
||||
.sink(receiveValue: { composerMode in
|
||||
XCTAssertEqual(composerMode, mode)
|
||||
expectation.fulfill()
|
||||
})
|
||||
|
||||
viewModel.process(roomAction: .setMode(mode: mode))
|
||||
|
||||
wait(for: [expectation], timeout: 2.0)
|
||||
cancellable.cancel()
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,14 @@
|
||||
//
|
||||
|
||||
@testable import ElementX
|
||||
|
||||
import Combine
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
class RoomScreenViewModelTests: XCTestCase {
|
||||
var userIndicatorControllerMock: UserIndicatorControllerMock!
|
||||
var cancellables = Set<AnyCancellable>()
|
||||
|
||||
override func setUp() async throws {
|
||||
userIndicatorControllerMock = UserIndicatorControllerMock.default
|
||||
@@ -195,15 +198,17 @@ class RoomScreenViewModelTests: XCTestCase {
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: userIndicatorControllerMock)
|
||||
viewModel.callback = { action in
|
||||
switch action {
|
||||
case .displayRoomMemberDetails(let member):
|
||||
XCTAssert(member === roomMemberMock)
|
||||
default:
|
||||
XCTFail("Did not received the expected action")
|
||||
viewModel.actions
|
||||
.sink { action in
|
||||
switch action {
|
||||
case .displayRoomMemberDetails(let member):
|
||||
XCTAssert(member === roomMemberMock)
|
||||
default:
|
||||
XCTFail("Did not received the expected action")
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
expectation.fulfill()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
// Test
|
||||
viewModel.context.send(viewAction: .tappedOnUser(userID: "bob"))
|
||||
@@ -232,15 +237,17 @@ class RoomScreenViewModelTests: XCTestCase {
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: userIndicatorControllerMock)
|
||||
|
||||
viewModel.callback = { action in
|
||||
switch action {
|
||||
case .displayRoomMemberDetails(let member):
|
||||
XCTAssert(member === roomMemberMock)
|
||||
expectation.fulfill()
|
||||
default:
|
||||
XCTFail("Did not received the expected action")
|
||||
viewModel.actions
|
||||
.sink { action in
|
||||
switch action {
|
||||
case .displayRoomMemberDetails(let member):
|
||||
XCTAssert(member === roomMemberMock)
|
||||
expectation.fulfill()
|
||||
default:
|
||||
XCTFail("Did not received the expected action")
|
||||
}
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
// Test
|
||||
viewModel.context.send(viewAction: .tappedOnUser(userID: "bob"))
|
||||
@@ -268,9 +275,11 @@ class RoomScreenViewModelTests: XCTestCase {
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: userIndicatorControllerMock)
|
||||
viewModel.callback = { _ in
|
||||
XCTFail("Should not receive any action")
|
||||
}
|
||||
viewModel.actions
|
||||
.sink { _ in
|
||||
XCTFail("Should not receive any action")
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
// Test
|
||||
let deferred = deferFulfillment(viewModel.context.$viewState.collect(2).first(),
|
||||
|
||||
Reference in New Issue
Block a user