From cffa3270dd33ed14bbfbdc30c842928bb7c96f04 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 13 Jun 2022 15:49:54 +0300 Subject: [PATCH 01/16] Create dummy data for poll view states. --- .../poll/create/CreatePollViewStates.kt | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewStates.kt diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewStates.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewStates.kt new file mode 100644 index 0000000000..ce27176db2 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewStates.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022 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. + */ + +package im.vector.app.features.poll.create + +import im.vector.app.features.poll.PollMode +import kotlin.random.Random + +object CreatePollViewStates { + + val fakeRoomId = "fakeRoomId" + val fakeEventId = "fakeEventId" + + val createPollArgs = CreatePollArgs(fakeRoomId, null, PollMode.CREATE) + val editPollArgs = CreatePollArgs(fakeRoomId, fakeEventId, PollMode.EDIT) + + val fakeQuestion = "What is your favourite coffee?" + val fakeOptions = List(CreatePollViewModel.MAX_OPTIONS_COUNT + 1) { "Coffee No${Random.nextInt()}" } + + val initialCreatePollViewState = CreatePollViewState(createPollArgs).copy( + canCreatePoll = false, + canAddMoreOptions = true + ) + + val pollViewStateWithOnlyQuestion = initialCreatePollViewState.copy( + question = fakeQuestion, + canCreatePoll = false, + canAddMoreOptions = true + ) + + val pollViewStateWithQuestionAndNotEnoughOptions = initialCreatePollViewState.copy( + question = fakeQuestion, + options = fakeOptions.take(CreatePollViewModel.MIN_OPTIONS_COUNT - 1).toMutableList().apply { add("") }, + canCreatePoll = false, + canAddMoreOptions = true + ) + + val pollViewStateWithoutQuestionAndEnoughOptions = initialCreatePollViewState.copy( + question = "", + options = fakeOptions.take(CreatePollViewModel.MIN_OPTIONS_COUNT), + canCreatePoll = false, + canAddMoreOptions = true + ) + + val pollViewStateWithQuestionAndEnoughOptions = initialCreatePollViewState.copy( + question = fakeQuestion, + options = fakeOptions.take(CreatePollViewModel.MIN_OPTIONS_COUNT), + canCreatePoll = true, + canAddMoreOptions = true + ) + + val pollViewStateWithQuestionAndMaxOptions = initialCreatePollViewState.copy( + question = fakeQuestion, + options = fakeOptions.take(CreatePollViewModel.MAX_OPTIONS_COUNT), + canCreatePoll = true, + canAddMoreOptions = false + ) +} From 19de21535bc9b104c453b8e2c89e6471ab6a0ef4 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 13 Jun 2022 15:53:25 +0300 Subject: [PATCH 02/16] Test initial poll view state. --- .../poll/create/CreatePollViewModelTest.kt | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt new file mode 100644 index 0000000000..eceb4a7c13 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 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. + */ + +package im.vector.app.features.poll.create + +import com.airbnb.mvrx.test.MvRxTestRule +import im.vector.app.features.poll.PollMode +import im.vector.app.features.poll.create.CreatePollViewStates.createPollArgs +import im.vector.app.features.poll.create.CreatePollViewStates.editPollArgs +import im.vector.app.features.poll.create.CreatePollViewStates.fakeOptions +import im.vector.app.features.poll.create.CreatePollViewStates.fakeQuestion +import im.vector.app.features.poll.create.CreatePollViewStates.initialCreatePollViewState +import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithOnlyQuestion +import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndNotEnoughOptions +import im.vector.app.test.fakes.FakeSession +import im.vector.app.test.test +import org.junit.Rule +import org.junit.Test +import kotlin.random.Random + +class CreatePollViewModelTest { + + @get:Rule + val mvrxTestRule = MvRxTestRule() + + private val fakeSession = FakeSession() + + private fun createPollViewModel(pollMode: PollMode): CreatePollViewModel { + return if (pollMode == PollMode.EDIT) { + CreatePollViewModel(CreatePollViewState(editPollArgs), fakeSession) + } else { + CreatePollViewModel(CreatePollViewState(createPollArgs), fakeSession) + } + } + + @Test + fun `given the view model is initialized then poll cannot be created and options can be added`() { + val createPollViewModel = createPollViewModel(PollMode.CREATE) + createPollViewModel + .test() + .assertState(initialCreatePollViewState) + .finish() + } +} From 5b35534c3d5f6f78c0c7fbbb1ce512801005c40b Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 13 Jun 2022 15:54:33 +0300 Subject: [PATCH 03/16] Test poll view state without enough options. --- .../poll/create/CreatePollViewModelTest.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt index eceb4a7c13..456911e1e8 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt @@ -54,4 +54,29 @@ class CreatePollViewModelTest { .assertState(initialCreatePollViewState) .finish() } + + @Test + fun `given there is not any options when the question is added then poll cannot be created and options can be added`() { + val createPollViewModel = createPollViewModel(PollMode.CREATE) + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) + + createPollViewModel + .test() + .assertState(pollViewStateWithOnlyQuestion) + .finish() + } + + @Test + fun `given there is not enough options when the question is added then poll cannot be created and options can be added`() { + val createPollViewModel = createPollViewModel(PollMode.CREATE) + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) + repeat(CreatePollViewModel.MIN_OPTIONS_COUNT - 1) { + createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, fakeOptions[it])) + } + + createPollViewModel + .test() + .assertState(pollViewStateWithQuestionAndNotEnoughOptions) + .finish() + } } From 0bf37abca15dd3cb69936751405135543da8ec9b Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 13 Jun 2022 15:58:13 +0300 Subject: [PATCH 04/16] Test poll views state with enough number of options but without a question. --- .../poll/create/CreatePollViewModelTest.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt index 456911e1e8..4381035b6f 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt @@ -25,6 +25,7 @@ import im.vector.app.features.poll.create.CreatePollViewStates.fakeQuestion import im.vector.app.features.poll.create.CreatePollViewStates.initialCreatePollViewState import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithOnlyQuestion import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndNotEnoughOptions +import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithoutQuestionAndEnoughOptions import im.vector.app.test.fakes.FakeSession import im.vector.app.test.test import org.junit.Rule @@ -79,4 +80,17 @@ class CreatePollViewModelTest { .assertState(pollViewStateWithQuestionAndNotEnoughOptions) .finish() } + + @Test + fun `given there is not a question when enough options are added then poll cannot be created and options can be added`() { + val createPollViewModel = createPollViewModel(PollMode.CREATE) + repeat(CreatePollViewModel.MIN_OPTIONS_COUNT) { + createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, fakeOptions[it])) + } + + createPollViewModel + .test() + .assertState(pollViewStateWithoutQuestionAndEnoughOptions) + .finish() + } } From 1f04e73fcb482ff706411f9e89760bbea51fe8b5 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 13 Jun 2022 17:49:57 +0300 Subject: [PATCH 05/16] Test poll view state with a question and enough number of options. --- .../poll/create/CreatePollViewModelTest.kt | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt index 4381035b6f..ee6fb8db18 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt @@ -17,6 +17,7 @@ package im.vector.app.features.poll.create import com.airbnb.mvrx.test.MvRxTestRule +import im.vector.app.features.login.SignMode import im.vector.app.features.poll.PollMode import im.vector.app.features.poll.create.CreatePollViewStates.createPollArgs import im.vector.app.features.poll.create.CreatePollViewStates.editPollArgs @@ -24,13 +25,14 @@ import im.vector.app.features.poll.create.CreatePollViewStates.fakeOptions import im.vector.app.features.poll.create.CreatePollViewStates.fakeQuestion import im.vector.app.features.poll.create.CreatePollViewStates.initialCreatePollViewState import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithOnlyQuestion +import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndEnoughOptions import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndNotEnoughOptions import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithoutQuestionAndEnoughOptions import im.vector.app.test.fakes.FakeSession import im.vector.app.test.test +import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -import kotlin.random.Random class CreatePollViewModelTest { @@ -48,7 +50,7 @@ class CreatePollViewModelTest { } @Test - fun `given the view model is initialized then poll cannot be created and options can be added`() { + fun `given the view model is initialized then poll cannot be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) createPollViewModel .test() @@ -57,7 +59,7 @@ class CreatePollViewModelTest { } @Test - fun `given there is not any options when the question is added then poll cannot be created and options can be added`() { + fun `given there is not any options when the question is added then poll cannot be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) @@ -68,7 +70,7 @@ class CreatePollViewModelTest { } @Test - fun `given there is not enough options when the question is added then poll cannot be created and options can be added`() { + fun `given there is not enough options when the question is added then poll cannot be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) repeat(CreatePollViewModel.MIN_OPTIONS_COUNT - 1) { @@ -82,7 +84,7 @@ class CreatePollViewModelTest { } @Test - fun `given there is not a question when enough options are added then poll cannot be created and options can be added`() { + fun `given there is not a question when enough options are added then poll cannot be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) repeat(CreatePollViewModel.MIN_OPTIONS_COUNT) { createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, fakeOptions[it])) @@ -93,4 +95,18 @@ class CreatePollViewModelTest { .assertState(pollViewStateWithoutQuestionAndEnoughOptions) .finish() } + + @Test + fun `given there is a question when enough options are added then poll can be created and more options can be added`() = runTest { + val createPollViewModel = createPollViewModel(PollMode.CREATE) + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) + repeat(CreatePollViewModel.MIN_OPTIONS_COUNT) { + createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, fakeOptions[it])) + } + + createPollViewModel + .test() + .assertState(pollViewStateWithQuestionAndEnoughOptions) + .finish() + } } From 0ed9a1885c06b6621c5ba36e487dbeb339b51ae4 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 15 Jun 2022 15:55:02 +0300 Subject: [PATCH 06/16] Test poll view state with a question and max number of options. --- .../poll/create/CreatePollViewModelTest.kt | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt index ee6fb8db18..017ed0a31c 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt @@ -17,7 +17,6 @@ package im.vector.app.features.poll.create import com.airbnb.mvrx.test.MvRxTestRule -import im.vector.app.features.login.SignMode import im.vector.app.features.poll.PollMode import im.vector.app.features.poll.create.CreatePollViewStates.createPollArgs import im.vector.app.features.poll.create.CreatePollViewStates.editPollArgs @@ -26,10 +25,12 @@ import im.vector.app.features.poll.create.CreatePollViewStates.fakeQuestion import im.vector.app.features.poll.create.CreatePollViewStates.initialCreatePollViewState import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithOnlyQuestion import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndEnoughOptions +import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndMaxOptions import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndNotEnoughOptions import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithoutQuestionAndEnoughOptions import im.vector.app.test.fakes.FakeSession import im.vector.app.test.test +import kotlinx.coroutines.delay import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -63,6 +64,8 @@ class CreatePollViewModelTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) + // We need to wait for createPollViewModel.onChange is triggered + delay(10) createPollViewModel .test() .assertState(pollViewStateWithOnlyQuestion) @@ -77,6 +80,7 @@ class CreatePollViewModelTest { createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, fakeOptions[it])) } + delay(10) createPollViewModel .test() .assertState(pollViewStateWithQuestionAndNotEnoughOptions) @@ -90,6 +94,7 @@ class CreatePollViewModelTest { createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, fakeOptions[it])) } + delay(10) createPollViewModel .test() .assertState(pollViewStateWithoutQuestionAndEnoughOptions) @@ -104,9 +109,28 @@ class CreatePollViewModelTest { createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, fakeOptions[it])) } + delay(10) createPollViewModel .test() .assertState(pollViewStateWithQuestionAndEnoughOptions) .finish() } + + @Test + fun `given there is a question when max number of options are added then poll can be created and more options cannot be added`() = runTest { + val createPollViewModel = createPollViewModel(PollMode.CREATE) + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) + repeat(CreatePollViewModel.MAX_OPTIONS_COUNT) { + if (it >= CreatePollViewModel.MIN_OPTIONS_COUNT) { + createPollViewModel.handle(CreatePollAction.OnAddOption) + } + createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, fakeOptions[it])) + } + + delay(10) + createPollViewModel + .test() + .assertState(pollViewStateWithQuestionAndMaxOptions) + .finish() + } } From 24d59eba87b0cd5397dbe5864d11d5e7679a41bb Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 15 Jun 2022 17:51:13 +0300 Subject: [PATCH 07/16] Test poll view events when create poll is requested. --- .../poll/create/CreatePollViewModelTest.kt | 70 ++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt index 017ed0a31c..fa24d9c4a6 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt @@ -22,25 +22,38 @@ import im.vector.app.features.poll.create.CreatePollViewStates.createPollArgs import im.vector.app.features.poll.create.CreatePollViewStates.editPollArgs import im.vector.app.features.poll.create.CreatePollViewStates.fakeOptions import im.vector.app.features.poll.create.CreatePollViewStates.fakeQuestion +import im.vector.app.features.poll.create.CreatePollViewStates.fakeRoomId import im.vector.app.features.poll.create.CreatePollViewStates.initialCreatePollViewState import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithOnlyQuestion import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndEnoughOptions import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndMaxOptions import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndNotEnoughOptions import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithoutQuestionAndEnoughOptions -import im.vector.app.test.fakes.FakeSession import im.vector.app.test.test +import io.mockk.every +import io.mockk.mockk import kotlinx.coroutines.delay import kotlinx.coroutines.test.runTest +import org.amshove.kluent.shouldBe +import org.junit.Before import org.junit.Rule import org.junit.Test +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.Room +import org.matrix.android.sdk.api.session.room.model.message.PollType +import org.matrix.android.sdk.api.session.room.send.SendService +import org.matrix.android.sdk.api.util.Cancelable class CreatePollViewModelTest { @get:Rule val mvrxTestRule = MvRxTestRule() - private val fakeSession = FakeSession() + private val fakeSession = mockk() + private val fakeRoom = mockk() + private val fakeSendService = mockk() + private val fakeCancellable = mockk() private fun createPollViewModel(pollMode: PollMode): CreatePollViewModel { return if (pollMode == PollMode.EDIT) { @@ -50,6 +63,13 @@ class CreatePollViewModelTest { } } + @Before + fun setup() { + every { fakeSession.getRoom(fakeRoomId) } returns fakeRoom + every { fakeRoom.sendService() } returns fakeSendService + every { fakeSendService.sendPoll(any(), fakeQuestion, any()) } returns fakeCancellable + } + @Test fun `given the view model is initialized then poll cannot be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) @@ -133,4 +153,50 @@ class CreatePollViewModelTest { .assertState(pollViewStateWithQuestionAndMaxOptions) .finish() } + + @Test + fun `given an initial poll state when poll type is changed then view state is updated accordingly`() = runTest { + val createPollViewModel = createPollViewModel(PollMode.CREATE) + createPollViewModel.handle(CreatePollAction.OnPollTypeChanged(PollType.DISCLOSED)) + createPollViewModel.awaitState().pollType shouldBe PollType.DISCLOSED + createPollViewModel.handle(CreatePollAction.OnPollTypeChanged(PollType.UNDISCLOSED)) + createPollViewModel.awaitState().pollType shouldBe PollType.UNDISCLOSED + } + + @Test + fun `given there is not a question and enough options when create poll is requested then error view events are post`() = runTest { + val createPollViewModel = createPollViewModel(PollMode.CREATE) + val test = createPollViewModel.test() + + createPollViewModel.handle(CreatePollAction.OnCreatePoll) + + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) + createPollViewModel.handle(CreatePollAction.OnCreatePoll) + + createPollViewModel.handle(CreatePollAction.OnOptionChanged(0, fakeOptions[0])) + createPollViewModel.handle(CreatePollAction.OnCreatePoll) + + test + .assertEvents( + CreatePollViewEvents.EmptyQuestionError, + CreatePollViewEvents.NotEnoughOptionsError(requiredOptionsCount = CreatePollViewModel.MIN_OPTIONS_COUNT), + CreatePollViewEvents.NotEnoughOptionsError(requiredOptionsCount = CreatePollViewModel.MIN_OPTIONS_COUNT) + ) + } + + @Test + fun `given there is a question and enough options when create poll is requested then success view event is post`() = runTest { + val createPollViewModel = createPollViewModel(PollMode.CREATE) + val test = createPollViewModel.test() + + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) + createPollViewModel.handle(CreatePollAction.OnOptionChanged(0, fakeOptions[0])) + createPollViewModel.handle(CreatePollAction.OnOptionChanged(1, fakeOptions[1])) + createPollViewModel.handle(CreatePollAction.OnCreatePoll) + + test + .assertEvents( + CreatePollViewEvents.Success + ) + } } From 934d860bea7655319ff20aa4728e9b3e6a6a456e Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 15 Jun 2022 21:25:44 +0300 Subject: [PATCH 08/16] Changelog added. --- changelog.d/6320.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6320.misc diff --git a/changelog.d/6320.misc b/changelog.d/6320.misc new file mode 100644 index 0000000000..7cdd41f486 --- /dev/null +++ b/changelog.d/6320.misc @@ -0,0 +1 @@ +CreatePollViewModel unit tests From ec3248d7146300de7a661e22db18e73fcdfd74cd Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 15 Jun 2022 21:34:04 +0300 Subject: [PATCH 09/16] Lint fixes. --- .../vector/app/features/poll/create/CreatePollViewStates.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewStates.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewStates.kt index ce27176db2..518beabd1f 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewStates.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewStates.kt @@ -21,13 +21,13 @@ import kotlin.random.Random object CreatePollViewStates { - val fakeRoomId = "fakeRoomId" - val fakeEventId = "fakeEventId" + const val fakeRoomId = "fakeRoomId" + const val fakeEventId = "fakeEventId" val createPollArgs = CreatePollArgs(fakeRoomId, null, PollMode.CREATE) val editPollArgs = CreatePollArgs(fakeRoomId, fakeEventId, PollMode.EDIT) - val fakeQuestion = "What is your favourite coffee?" + const val fakeQuestion = "What is your favourite coffee?" val fakeOptions = List(CreatePollViewModel.MAX_OPTIONS_COUNT + 1) { "Coffee No${Random.nextInt()}" } val initialCreatePollViewState = CreatePollViewState(createPollArgs).copy( From 94c0a020fb45b38e2656d33a267d504a12e2901f Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 16 Jun 2022 13:39:32 +0300 Subject: [PATCH 10/16] Rename test data class. --- .../poll/create/CreatePollViewStates.kt | 71 ---------- .../poll/create/FakeCreatePollViewStates.kt | 122 ++++++++++++++++++ 2 files changed, 122 insertions(+), 71 deletions(-) delete mode 100644 vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewStates.kt create mode 100644 vector/src/test/java/im/vector/app/features/poll/create/FakeCreatePollViewStates.kt diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewStates.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewStates.kt deleted file mode 100644 index 518beabd1f..0000000000 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewStates.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2022 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. - */ - -package im.vector.app.features.poll.create - -import im.vector.app.features.poll.PollMode -import kotlin.random.Random - -object CreatePollViewStates { - - const val fakeRoomId = "fakeRoomId" - const val fakeEventId = "fakeEventId" - - val createPollArgs = CreatePollArgs(fakeRoomId, null, PollMode.CREATE) - val editPollArgs = CreatePollArgs(fakeRoomId, fakeEventId, PollMode.EDIT) - - const val fakeQuestion = "What is your favourite coffee?" - val fakeOptions = List(CreatePollViewModel.MAX_OPTIONS_COUNT + 1) { "Coffee No${Random.nextInt()}" } - - val initialCreatePollViewState = CreatePollViewState(createPollArgs).copy( - canCreatePoll = false, - canAddMoreOptions = true - ) - - val pollViewStateWithOnlyQuestion = initialCreatePollViewState.copy( - question = fakeQuestion, - canCreatePoll = false, - canAddMoreOptions = true - ) - - val pollViewStateWithQuestionAndNotEnoughOptions = initialCreatePollViewState.copy( - question = fakeQuestion, - options = fakeOptions.take(CreatePollViewModel.MIN_OPTIONS_COUNT - 1).toMutableList().apply { add("") }, - canCreatePoll = false, - canAddMoreOptions = true - ) - - val pollViewStateWithoutQuestionAndEnoughOptions = initialCreatePollViewState.copy( - question = "", - options = fakeOptions.take(CreatePollViewModel.MIN_OPTIONS_COUNT), - canCreatePoll = false, - canAddMoreOptions = true - ) - - val pollViewStateWithQuestionAndEnoughOptions = initialCreatePollViewState.copy( - question = fakeQuestion, - options = fakeOptions.take(CreatePollViewModel.MIN_OPTIONS_COUNT), - canCreatePoll = true, - canAddMoreOptions = true - ) - - val pollViewStateWithQuestionAndMaxOptions = initialCreatePollViewState.copy( - question = fakeQuestion, - options = fakeOptions.take(CreatePollViewModel.MAX_OPTIONS_COUNT), - canCreatePoll = true, - canAddMoreOptions = false - ) -} diff --git a/vector/src/test/java/im/vector/app/features/poll/create/FakeCreatePollViewStates.kt b/vector/src/test/java/im/vector/app/features/poll/create/FakeCreatePollViewStates.kt new file mode 100644 index 0000000000..b384a9a257 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/poll/create/FakeCreatePollViewStates.kt @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2022 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. + */ + +package im.vector.app.features.poll.create + +import im.vector.app.features.poll.PollMode +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent +import org.matrix.android.sdk.api.session.room.model.message.PollAnswer +import org.matrix.android.sdk.api.session.room.model.message.PollCreationInfo +import org.matrix.android.sdk.api.session.room.model.message.PollQuestion +import org.matrix.android.sdk.api.session.room.sender.SenderInfo +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import kotlin.random.Random + +object FakeCreatePollViewStates { + + const val A_FAKE_ROOM_ID = "fakeRoomId" + private const val A_FAKE_EVENT_ID = "fakeEventId" + private const val A_FAKE_USER_ID = "fakeUserId" + + val createPollArgs = CreatePollArgs(A_FAKE_ROOM_ID, null, PollMode.CREATE) + val editPollArgs = CreatePollArgs(A_FAKE_ROOM_ID, A_FAKE_EVENT_ID, PollMode.EDIT) + + const val A_FAKE_QUESTION = "What is your favourite coffee?" + val A_FAKE_OPTIONS = List(CreatePollViewModel.MAX_OPTIONS_COUNT + 1) { "Coffee No${Random.nextInt()}" } + + private val A_POLL_CONTENT = MessagePollContent( + unstablePollCreationInfo = PollCreationInfo( + question = PollQuestion( + unstableQuestion = A_FAKE_QUESTION + ), + maxSelections = 1, + answers = listOf( + PollAnswer( + id = "5ef5f7b0-c9a1-49cf-a0b3-374729a43e76", + unstableAnswer = A_FAKE_OPTIONS[0] + ), + PollAnswer( + id = "ec1a4db0-46d8-4d7a-9bb6-d80724715938", + unstableAnswer = A_FAKE_OPTIONS[1] + ) + ) + ) + ) + + private val A_POLL_START_EVENT = Event( + type = EventType.POLL_START.first(), + eventId = A_FAKE_EVENT_ID, + originServerTs = 1652435922563, + senderId = A_FAKE_USER_ID, + roomId = A_FAKE_ROOM_ID, + content = A_POLL_CONTENT.toContent() + ) + + val A_POLL_START_TIMELINE_EVENT = TimelineEvent( + root = A_POLL_START_EVENT, + localId = 12345, + eventId = A_FAKE_EVENT_ID, + displayIndex = 1, + senderInfo = SenderInfo(A_FAKE_USER_ID, isUniqueDisplayName = true, avatarUrl = "", displayName = "") + ) + + val initialCreatePollViewState = CreatePollViewState(createPollArgs).copy( + canCreatePoll = false, + canAddMoreOptions = true + ) + + val pollViewStateWithOnlyQuestion = initialCreatePollViewState.copy( + question = A_FAKE_QUESTION, + canCreatePoll = false, + canAddMoreOptions = true + ) + + val pollViewStateWithQuestionAndNotEnoughOptions = initialCreatePollViewState.copy( + question = A_FAKE_QUESTION, + options = A_FAKE_OPTIONS.take(CreatePollViewModel.MIN_OPTIONS_COUNT - 1).toMutableList().apply { add("") }, + canCreatePoll = false, + canAddMoreOptions = true + ) + + val pollViewStateWithoutQuestionAndEnoughOptions = initialCreatePollViewState.copy( + question = "", + options = A_FAKE_OPTIONS.take(CreatePollViewModel.MIN_OPTIONS_COUNT), + canCreatePoll = false, + canAddMoreOptions = true + ) + + val pollViewStateWithQuestionAndEnoughOptions = initialCreatePollViewState.copy( + question = A_FAKE_QUESTION, + options = A_FAKE_OPTIONS.take(CreatePollViewModel.MIN_OPTIONS_COUNT), + canCreatePoll = true, + canAddMoreOptions = true + ) + + val pollViewStateWithQuestionAndMaxOptions = initialCreatePollViewState.copy( + question = A_FAKE_QUESTION, + options = A_FAKE_OPTIONS.take(CreatePollViewModel.MAX_OPTIONS_COUNT), + canCreatePoll = true, + canAddMoreOptions = false + ) + + val editedPollViewState = pollViewStateWithQuestionAndEnoughOptions.copy( + editedEventId = A_FAKE_EVENT_ID, + mode = PollMode.EDIT + ) +} From b558d14a48be81ce3791767713f2451c9d814fd1 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 16 Jun 2022 13:40:00 +0300 Subject: [PATCH 11/16] Create fake room services. --- .../app/test/fakes/FakeRelationService.kt | 30 +++++++++++++++++++ .../java/im/vector/app/test/fakes/FakeRoom.kt | 9 ++++++ .../vector/app/test/fakes/FakeSendService.kt | 29 ++++++++++++++++++ .../app/test/fakes/FakeTimelineService.kt | 29 ++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 vector/src/test/java/im/vector/app/test/fakes/FakeRelationService.kt create mode 100644 vector/src/test/java/im/vector/app/test/fakes/FakeSendService.kt create mode 100644 vector/src/test/java/im/vector/app/test/fakes/FakeTimelineService.kt diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeRelationService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeRelationService.kt new file mode 100644 index 0000000000..828e3a25b6 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeRelationService.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021 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. + */ + +package im.vector.app.test.fakes + +import io.mockk.mockk +import org.matrix.android.sdk.api.session.room.model.message.PollType +import org.matrix.android.sdk.api.session.room.model.relation.RelationService +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.api.util.Cancelable + +class FakeRelationService : RelationService by mockk() { + + private val cancelable = mockk() + + override fun editPoll(targetEvent: TimelineEvent, pollType: PollType, question: String, options: List): Cancelable = cancelable +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeRoom.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeRoom.kt index ff87ab0fde..865b01551a 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeRoom.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeRoom.kt @@ -21,7 +21,16 @@ import org.matrix.android.sdk.api.session.room.Room class FakeRoom( private val fakeLocationSharingService: FakeLocationSharingService = FakeLocationSharingService(), + private val fakeSendService: FakeSendService = FakeSendService(), + private val fakeTimelineService: FakeTimelineService = FakeTimelineService(), + private val fakeRelationService: FakeRelationService = FakeRelationService(), ) : Room by mockk() { override fun locationSharingService() = fakeLocationSharingService + + override fun sendService() = fakeSendService + + override fun timelineService() = fakeTimelineService + + override fun relationService() = fakeRelationService } diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSendService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSendService.kt new file mode 100644 index 0000000000..04b9b95ce1 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSendService.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 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. + */ + +package im.vector.app.test.fakes + +import io.mockk.mockk +import org.matrix.android.sdk.api.session.room.model.message.PollType +import org.matrix.android.sdk.api.session.room.send.SendService +import org.matrix.android.sdk.api.util.Cancelable + +class FakeSendService : SendService by mockk() { + + private val cancelable = mockk() + + override fun sendPoll(pollType: PollType, question: String, options: List): Cancelable = cancelable +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeTimelineService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeTimelineService.kt new file mode 100644 index 0000000000..56f38724b1 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeTimelineService.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 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. + */ + +package im.vector.app.test.fakes + +import io.mockk.every +import io.mockk.mockk +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.api.session.room.timeline.TimelineService + +class FakeTimelineService : TimelineService by mockk() { + + fun givenTimelineEvent(event: TimelineEvent) { + every { getTimelineEvent(any()) } returns event + } +} From 841b63b8193d919e624066420a9f834e0c8e350b Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 16 Jun 2022 13:40:39 +0300 Subject: [PATCH 12/16] Test poll view events when poll is edited. --- .../poll/create/CreatePollViewModelTest.kt | 98 ++++++++++++------- 1 file changed, 61 insertions(+), 37 deletions(-) diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt index fa24d9c4a6..f73175faa3 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt @@ -18,42 +18,38 @@ package im.vector.app.features.poll.create import com.airbnb.mvrx.test.MvRxTestRule import im.vector.app.features.poll.PollMode -import im.vector.app.features.poll.create.CreatePollViewStates.createPollArgs -import im.vector.app.features.poll.create.CreatePollViewStates.editPollArgs -import im.vector.app.features.poll.create.CreatePollViewStates.fakeOptions -import im.vector.app.features.poll.create.CreatePollViewStates.fakeQuestion -import im.vector.app.features.poll.create.CreatePollViewStates.fakeRoomId -import im.vector.app.features.poll.create.CreatePollViewStates.initialCreatePollViewState -import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithOnlyQuestion -import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndEnoughOptions -import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndMaxOptions -import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithQuestionAndNotEnoughOptions -import im.vector.app.features.poll.create.CreatePollViewStates.pollViewStateWithoutQuestionAndEnoughOptions +import im.vector.app.features.poll.create.FakeCreatePollViewStates.A_FAKE_OPTIONS +import im.vector.app.features.poll.create.FakeCreatePollViewStates.A_FAKE_QUESTION +import im.vector.app.features.poll.create.FakeCreatePollViewStates.A_FAKE_ROOM_ID +import im.vector.app.features.poll.create.FakeCreatePollViewStates.A_POLL_START_TIMELINE_EVENT +import im.vector.app.features.poll.create.FakeCreatePollViewStates.createPollArgs +import im.vector.app.features.poll.create.FakeCreatePollViewStates.editPollArgs +import im.vector.app.features.poll.create.FakeCreatePollViewStates.editedPollViewState +import im.vector.app.features.poll.create.FakeCreatePollViewStates.initialCreatePollViewState +import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithOnlyQuestion +import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithQuestionAndEnoughOptions +import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithQuestionAndMaxOptions +import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithQuestionAndNotEnoughOptions +import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithoutQuestionAndEnoughOptions +import im.vector.app.test.fakes.FakeSession import im.vector.app.test.test -import io.mockk.every -import io.mockk.mockk +import io.mockk.unmockkAll import kotlinx.coroutines.delay import kotlinx.coroutines.test.runTest import org.amshove.kluent.shouldBe +import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test -import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.getRoom -import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.model.message.PollType -import org.matrix.android.sdk.api.session.room.send.SendService -import org.matrix.android.sdk.api.util.Cancelable class CreatePollViewModelTest { @get:Rule val mvrxTestRule = MvRxTestRule() - private val fakeSession = mockk() - private val fakeRoom = mockk() - private val fakeSendService = mockk() - private val fakeCancellable = mockk() + private val fakeSession = FakeSession() private fun createPollViewModel(pollMode: PollMode): CreatePollViewModel { return if (pollMode == PollMode.EDIT) { @@ -65,9 +61,16 @@ class CreatePollViewModelTest { @Before fun setup() { - every { fakeSession.getRoom(fakeRoomId) } returns fakeRoom - every { fakeRoom.sendService() } returns fakeSendService - every { fakeSendService.sendPoll(any(), fakeQuestion, any()) } returns fakeCancellable + fakeSession + .roomService() + .getRoom(A_FAKE_ROOM_ID) + .timelineService() + .givenTimelineEvent(A_POLL_START_TIMELINE_EVENT) + } + + @After + fun tearDown() { + unmockkAll() } @Test @@ -82,7 +85,7 @@ class CreatePollViewModelTest { @Test fun `given there is not any options when the question is added then poll cannot be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) - createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(A_FAKE_QUESTION)) // We need to wait for createPollViewModel.onChange is triggered delay(10) @@ -95,9 +98,9 @@ class CreatePollViewModelTest { @Test fun `given there is not enough options when the question is added then poll cannot be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) - createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(A_FAKE_QUESTION)) repeat(CreatePollViewModel.MIN_OPTIONS_COUNT - 1) { - createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, fakeOptions[it])) + createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, A_FAKE_OPTIONS[it])) } delay(10) @@ -111,7 +114,7 @@ class CreatePollViewModelTest { fun `given there is not a question when enough options are added then poll cannot be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) repeat(CreatePollViewModel.MIN_OPTIONS_COUNT) { - createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, fakeOptions[it])) + createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, A_FAKE_OPTIONS[it])) } delay(10) @@ -124,9 +127,9 @@ class CreatePollViewModelTest { @Test fun `given there is a question when enough options are added then poll can be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) - createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(A_FAKE_QUESTION)) repeat(CreatePollViewModel.MIN_OPTIONS_COUNT) { - createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, fakeOptions[it])) + createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, A_FAKE_OPTIONS[it])) } delay(10) @@ -139,12 +142,12 @@ class CreatePollViewModelTest { @Test fun `given there is a question when max number of options are added then poll can be created and more options cannot be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) - createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(A_FAKE_QUESTION)) repeat(CreatePollViewModel.MAX_OPTIONS_COUNT) { if (it >= CreatePollViewModel.MIN_OPTIONS_COUNT) { createPollViewModel.handle(CreatePollAction.OnAddOption) } - createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, fakeOptions[it])) + createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, A_FAKE_OPTIONS[it])) } delay(10) @@ -170,10 +173,10 @@ class CreatePollViewModelTest { createPollViewModel.handle(CreatePollAction.OnCreatePoll) - createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(A_FAKE_QUESTION)) createPollViewModel.handle(CreatePollAction.OnCreatePoll) - createPollViewModel.handle(CreatePollAction.OnOptionChanged(0, fakeOptions[0])) + createPollViewModel.handle(CreatePollAction.OnOptionChanged(0, A_FAKE_OPTIONS[0])) createPollViewModel.handle(CreatePollAction.OnCreatePoll) test @@ -189,9 +192,30 @@ class CreatePollViewModelTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) val test = createPollViewModel.test() - createPollViewModel.handle(CreatePollAction.OnQuestionChanged(fakeQuestion)) - createPollViewModel.handle(CreatePollAction.OnOptionChanged(0, fakeOptions[0])) - createPollViewModel.handle(CreatePollAction.OnOptionChanged(1, fakeOptions[1])) + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(A_FAKE_QUESTION)) + createPollViewModel.handle(CreatePollAction.OnOptionChanged(0, A_FAKE_OPTIONS[0])) + createPollViewModel.handle(CreatePollAction.OnOptionChanged(1, A_FAKE_OPTIONS[1])) + createPollViewModel.handle(CreatePollAction.OnCreatePoll) + + test + .assertEvents( + CreatePollViewEvents.Success + ) + } + + @Test + fun `given an edited poll event when question and options are changed then view state is updated accordingly`() = runTest { + val createPollViewModel = createPollViewModel(PollMode.EDIT) + + delay(10) + createPollViewModel.test().assertState(editedPollViewState) + } + + @Test + fun `given an edited poll event then able to be edited`() = runTest { + val createPollViewModel = createPollViewModel(PollMode.EDIT) + val test = createPollViewModel.test() + createPollViewModel.handle(CreatePollAction.OnCreatePoll) test From f13dfb829169dbd70ec26b7572b2a258869428a7 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 16 Jun 2022 14:11:17 +0300 Subject: [PATCH 13/16] Test poll view state when poll option is deleted. --- .../poll/create/CreatePollViewModelTest.kt | 15 ++++++++++++++- .../poll/create/FakeCreatePollViewStates.kt | 6 ++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt index f73175faa3..e0364b286f 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt @@ -28,6 +28,7 @@ import im.vector.app.features.poll.create.FakeCreatePollViewStates.editedPollVie import im.vector.app.features.poll.create.FakeCreatePollViewStates.initialCreatePollViewState import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithOnlyQuestion import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithQuestionAndEnoughOptions +import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithQuestionAndEnoughOptionsButDeletedLastOption import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithQuestionAndMaxOptions import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithQuestionAndNotEnoughOptions import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithoutQuestionAndEnoughOptions @@ -41,7 +42,6 @@ import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test -import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.model.message.PollType class CreatePollViewModelTest { @@ -203,6 +203,19 @@ class CreatePollViewModelTest { ) } + @Test + fun `given there is a question and enough options when the last option is deleted then view state should be updated accordingly`() = runTest { + val createPollViewModel = createPollViewModel(PollMode.CREATE) + + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(A_FAKE_QUESTION)) + createPollViewModel.handle(CreatePollAction.OnOptionChanged(0, A_FAKE_OPTIONS[0])) + createPollViewModel.handle(CreatePollAction.OnOptionChanged(1, A_FAKE_OPTIONS[1])) + createPollViewModel.handle(CreatePollAction.OnDeleteOption(1)) + + delay(10) + createPollViewModel.test().assertState(pollViewStateWithQuestionAndEnoughOptionsButDeletedLastOption) + } + @Test fun `given an edited poll event when question and options are changed then view state is updated accordingly`() = runTest { val createPollViewModel = createPollViewModel(PollMode.EDIT) diff --git a/vector/src/test/java/im/vector/app/features/poll/create/FakeCreatePollViewStates.kt b/vector/src/test/java/im/vector/app/features/poll/create/FakeCreatePollViewStates.kt index b384a9a257..e5eeb86b04 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/FakeCreatePollViewStates.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/FakeCreatePollViewStates.kt @@ -108,6 +108,12 @@ object FakeCreatePollViewStates { canAddMoreOptions = true ) + val pollViewStateWithQuestionAndEnoughOptionsButDeletedLastOption = pollViewStateWithQuestionAndEnoughOptions.copy( + options = A_FAKE_OPTIONS.take(CreatePollViewModel.MIN_OPTIONS_COUNT).toMutableList().apply { removeLast() }, + canCreatePoll = false, + canAddMoreOptions = true + ) + val pollViewStateWithQuestionAndMaxOptions = initialCreatePollViewState.copy( question = A_FAKE_QUESTION, options = A_FAKE_OPTIONS.take(CreatePollViewModel.MAX_OPTIONS_COUNT), From a1d35ae9e41c33df449c6cf1b9918dabc50337b0 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 16 Jun 2022 14:23:25 +0300 Subject: [PATCH 14/16] Move fake class into the right package. --- .../poll/create/CreatePollViewModelTest.kt | 28 +++++++++---------- .../fakes}/FakeCreatePollViewStates.kt | 5 +++- 2 files changed, 18 insertions(+), 15 deletions(-) rename vector/src/test/java/im/vector/app/{features/poll/create => test/fakes}/FakeCreatePollViewStates.kt (96%) diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt index e0364b286f..373fd77d40 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt @@ -18,20 +18,20 @@ package im.vector.app.features.poll.create import com.airbnb.mvrx.test.MvRxTestRule import im.vector.app.features.poll.PollMode -import im.vector.app.features.poll.create.FakeCreatePollViewStates.A_FAKE_OPTIONS -import im.vector.app.features.poll.create.FakeCreatePollViewStates.A_FAKE_QUESTION -import im.vector.app.features.poll.create.FakeCreatePollViewStates.A_FAKE_ROOM_ID -import im.vector.app.features.poll.create.FakeCreatePollViewStates.A_POLL_START_TIMELINE_EVENT -import im.vector.app.features.poll.create.FakeCreatePollViewStates.createPollArgs -import im.vector.app.features.poll.create.FakeCreatePollViewStates.editPollArgs -import im.vector.app.features.poll.create.FakeCreatePollViewStates.editedPollViewState -import im.vector.app.features.poll.create.FakeCreatePollViewStates.initialCreatePollViewState -import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithOnlyQuestion -import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithQuestionAndEnoughOptions -import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithQuestionAndEnoughOptionsButDeletedLastOption -import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithQuestionAndMaxOptions -import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithQuestionAndNotEnoughOptions -import im.vector.app.features.poll.create.FakeCreatePollViewStates.pollViewStateWithoutQuestionAndEnoughOptions +import im.vector.app.test.fakes.FakeCreatePollViewStates.A_FAKE_OPTIONS +import im.vector.app.test.fakes.FakeCreatePollViewStates.A_FAKE_QUESTION +import im.vector.app.test.fakes.FakeCreatePollViewStates.A_FAKE_ROOM_ID +import im.vector.app.test.fakes.FakeCreatePollViewStates.A_POLL_START_TIMELINE_EVENT +import im.vector.app.test.fakes.FakeCreatePollViewStates.createPollArgs +import im.vector.app.test.fakes.FakeCreatePollViewStates.editPollArgs +import im.vector.app.test.fakes.FakeCreatePollViewStates.editedPollViewState +import im.vector.app.test.fakes.FakeCreatePollViewStates.initialCreatePollViewState +import im.vector.app.test.fakes.FakeCreatePollViewStates.pollViewStateWithOnlyQuestion +import im.vector.app.test.fakes.FakeCreatePollViewStates.pollViewStateWithQuestionAndEnoughOptions +import im.vector.app.test.fakes.FakeCreatePollViewStates.pollViewStateWithQuestionAndEnoughOptionsButDeletedLastOption +import im.vector.app.test.fakes.FakeCreatePollViewStates.pollViewStateWithQuestionAndMaxOptions +import im.vector.app.test.fakes.FakeCreatePollViewStates.pollViewStateWithQuestionAndNotEnoughOptions +import im.vector.app.test.fakes.FakeCreatePollViewStates.pollViewStateWithoutQuestionAndEnoughOptions import im.vector.app.test.fakes.FakeSession import im.vector.app.test.test import io.mockk.unmockkAll diff --git a/vector/src/test/java/im/vector/app/features/poll/create/FakeCreatePollViewStates.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeCreatePollViewStates.kt similarity index 96% rename from vector/src/test/java/im/vector/app/features/poll/create/FakeCreatePollViewStates.kt rename to vector/src/test/java/im/vector/app/test/fakes/FakeCreatePollViewStates.kt index e5eeb86b04..04f3526602 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/FakeCreatePollViewStates.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeCreatePollViewStates.kt @@ -14,9 +14,12 @@ * limitations under the License. */ -package im.vector.app.features.poll.create +package im.vector.app.test.fakes import im.vector.app.features.poll.PollMode +import im.vector.app.features.poll.create.CreatePollArgs +import im.vector.app.features.poll.create.CreatePollViewModel +import im.vector.app.features.poll.create.CreatePollViewState import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toContent From 14a4a8edd79c5a50a737ef376c93e0e04956acea Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 16 Jun 2022 17:30:17 +0300 Subject: [PATCH 15/16] Workaround for mavericks bug (https://github.com/airbnb/mavericks/issues/599). --- .../features/poll/create/CreatePollViewModelTest.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt index 373fd77d40..16f6eeffbb 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt @@ -36,6 +36,7 @@ import im.vector.app.test.fakes.FakeSession import im.vector.app.test.test import io.mockk.unmockkAll import kotlinx.coroutines.delay +import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.amshove.kluent.shouldBe import org.junit.After @@ -47,7 +48,9 @@ import org.matrix.android.sdk.api.session.room.model.message.PollType class CreatePollViewModelTest { @get:Rule - val mvrxTestRule = MvRxTestRule() + val mvrxTestRule = MvRxTestRule( + testDispatcher = UnconfinedTestDispatcher() // See https://github.com/airbnb/mavericks/issues/599 + ) private val fakeSession = FakeSession() @@ -132,9 +135,8 @@ class CreatePollViewModelTest { createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, A_FAKE_OPTIONS[it])) } - delay(10) - createPollViewModel - .test() + //delay(10) + createPollViewModel.test() .assertState(pollViewStateWithQuestionAndEnoughOptions) .finish() } From 712a38e26a2c4d47874ed38878b94485ec618f3b Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 16 Jun 2022 18:27:00 +0300 Subject: [PATCH 16/16] Apply Maxime's fix to get latest state. --- .../poll/create/CreatePollViewModelTest.kt | 85 +++++++++++-------- .../java/im/vector/app/test/Extensions.kt | 5 ++ .../im/vector/app/test/FlowTestObserver.kt | 4 + 3 files changed, 57 insertions(+), 37 deletions(-) diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt index 16f6eeffbb..0387fc8986 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt @@ -35,10 +35,8 @@ import im.vector.app.test.fakes.FakeCreatePollViewStates.pollViewStateWithoutQue import im.vector.app.test.fakes.FakeSession import im.vector.app.test.test import io.mockk.unmockkAll -import kotlinx.coroutines.delay import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest -import org.amshove.kluent.shouldBe import org.junit.After import org.junit.Before import org.junit.Rule @@ -47,9 +45,11 @@ import org.matrix.android.sdk.api.session.room.model.message.PollType class CreatePollViewModelTest { + private val testDispatcher = UnconfinedTestDispatcher() + @get:Rule - val mvrxTestRule = MvRxTestRule( - testDispatcher = UnconfinedTestDispatcher() // See https://github.com/airbnb/mavericks/issues/599 + val mvRxTestRule = MvRxTestRule( + testDispatcher = testDispatcher // See https://github.com/airbnb/mavericks/issues/599 ) private val fakeSession = FakeSession() @@ -79,71 +79,74 @@ class CreatePollViewModelTest { @Test fun `given the view model is initialized then poll cannot be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) - createPollViewModel - .test() - .assertState(initialCreatePollViewState) + val test = createPollViewModel.test() + + test + .assertLatestState(initialCreatePollViewState) .finish() } @Test fun `given there is not any options when the question is added then poll cannot be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) + val test = createPollViewModel.test() + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(A_FAKE_QUESTION)) - // We need to wait for createPollViewModel.onChange is triggered - delay(10) - createPollViewModel - .test() - .assertState(pollViewStateWithOnlyQuestion) + test + .assertLatestState(pollViewStateWithOnlyQuestion) .finish() } @Test fun `given there is not enough options when the question is added then poll cannot be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) + val test = createPollViewModel.test() + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(A_FAKE_QUESTION)) repeat(CreatePollViewModel.MIN_OPTIONS_COUNT - 1) { createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, A_FAKE_OPTIONS[it])) } - delay(10) - createPollViewModel - .test() - .assertState(pollViewStateWithQuestionAndNotEnoughOptions) + test + .assertLatestState(pollViewStateWithQuestionAndNotEnoughOptions) .finish() } @Test fun `given there is not a question when enough options are added then poll cannot be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) + val test = createPollViewModel.test() + repeat(CreatePollViewModel.MIN_OPTIONS_COUNT) { createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, A_FAKE_OPTIONS[it])) } - delay(10) - createPollViewModel - .test() - .assertState(pollViewStateWithoutQuestionAndEnoughOptions) + test + .assertLatestState(pollViewStateWithoutQuestionAndEnoughOptions) .finish() } @Test fun `given there is a question when enough options are added then poll can be created and more options can be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) + val test = createPollViewModel.test() + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(A_FAKE_QUESTION)) repeat(CreatePollViewModel.MIN_OPTIONS_COUNT) { createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, A_FAKE_OPTIONS[it])) } - //delay(10) - createPollViewModel.test() - .assertState(pollViewStateWithQuestionAndEnoughOptions) + test + .assertLatestState(pollViewStateWithQuestionAndEnoughOptions) .finish() } @Test fun `given there is a question when max number of options are added then poll can be created and more options cannot be added`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) + val test = createPollViewModel.test() + createPollViewModel.handle(CreatePollAction.OnQuestionChanged(A_FAKE_QUESTION)) repeat(CreatePollViewModel.MAX_OPTIONS_COUNT) { if (it >= CreatePollViewModel.MIN_OPTIONS_COUNT) { @@ -152,20 +155,26 @@ class CreatePollViewModelTest { createPollViewModel.handle(CreatePollAction.OnOptionChanged(it, A_FAKE_OPTIONS[it])) } - delay(10) - createPollViewModel - .test() - .assertState(pollViewStateWithQuestionAndMaxOptions) + test + .assertLatestState(pollViewStateWithQuestionAndMaxOptions) .finish() } @Test fun `given an initial poll state when poll type is changed then view state is updated accordingly`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) - createPollViewModel.handle(CreatePollAction.OnPollTypeChanged(PollType.DISCLOSED)) - createPollViewModel.awaitState().pollType shouldBe PollType.DISCLOSED + val test = createPollViewModel.test() + createPollViewModel.handle(CreatePollAction.OnPollTypeChanged(PollType.UNDISCLOSED)) - createPollViewModel.awaitState().pollType shouldBe PollType.UNDISCLOSED + createPollViewModel.handle(CreatePollAction.OnPollTypeChanged(PollType.DISCLOSED)) + + test + .assertStatesChanges( + initialCreatePollViewState, + { copy(pollType = PollType.UNDISCLOSED) }, + { copy(pollType = PollType.DISCLOSED) }, + ) + .finish() } @Test @@ -185,7 +194,7 @@ class CreatePollViewModelTest { .assertEvents( CreatePollViewEvents.EmptyQuestionError, CreatePollViewEvents.NotEnoughOptionsError(requiredOptionsCount = CreatePollViewModel.MIN_OPTIONS_COUNT), - CreatePollViewEvents.NotEnoughOptionsError(requiredOptionsCount = CreatePollViewModel.MIN_OPTIONS_COUNT) + CreatePollViewEvents.NotEnoughOptionsError(requiredOptionsCount = CreatePollViewModel.MIN_OPTIONS_COUNT), ) } @@ -201,29 +210,31 @@ class CreatePollViewModelTest { test .assertEvents( - CreatePollViewEvents.Success + CreatePollViewEvents.Success, ) } @Test fun `given there is a question and enough options when the last option is deleted then view state should be updated accordingly`() = runTest { val createPollViewModel = createPollViewModel(PollMode.CREATE) + val test = createPollViewModel.test() createPollViewModel.handle(CreatePollAction.OnQuestionChanged(A_FAKE_QUESTION)) createPollViewModel.handle(CreatePollAction.OnOptionChanged(0, A_FAKE_OPTIONS[0])) createPollViewModel.handle(CreatePollAction.OnOptionChanged(1, A_FAKE_OPTIONS[1])) createPollViewModel.handle(CreatePollAction.OnDeleteOption(1)) - delay(10) - createPollViewModel.test().assertState(pollViewStateWithQuestionAndEnoughOptionsButDeletedLastOption) + test.assertLatestState(pollViewStateWithQuestionAndEnoughOptionsButDeletedLastOption) } @Test fun `given an edited poll event when question and options are changed then view state is updated accordingly`() = runTest { val createPollViewModel = createPollViewModel(PollMode.EDIT) + val test = createPollViewModel.test() - delay(10) - createPollViewModel.test().assertState(editedPollViewState) + test + .assertState(editedPollViewState) + .finish() } @Test @@ -235,7 +246,7 @@ class CreatePollViewModelTest { test .assertEvents( - CreatePollViewEvents.Success + CreatePollViewEvents.Success, ) } } diff --git a/vector/src/test/java/im/vector/app/test/Extensions.kt b/vector/src/test/java/im/vector/app/test/Extensions.kt index e5d5af2ece..5ac17cc5ff 100644 --- a/vector/src/test/java/im/vector/app/test/Extensions.kt +++ b/vector/src/test/java/im/vector/app/test/Extensions.kt @@ -86,6 +86,11 @@ class ViewModelTest( return this } + fun assertLatestState(expected: S): ViewModelTest { + states.assertLatestValue(expected) + return this + } + fun finish() { states.finish() viewEvents.finish() diff --git a/vector/src/test/java/im/vector/app/test/FlowTestObserver.kt b/vector/src/test/java/im/vector/app/test/FlowTestObserver.kt index 37f5f118c1..db828be232 100644 --- a/vector/src/test/java/im/vector/app/test/FlowTestObserver.kt +++ b/vector/src/test/java/im/vector/app/test/FlowTestObserver.kt @@ -47,6 +47,10 @@ class FlowTestObserver( return this } + fun assertLatestValue(value: T) { + assertTrue(values.last() == value) + } + fun assertValues(values: List): FlowTestObserver { assertEquals(values, this.values) return this