mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-12 02:30:25 +09:00
Fix | DND not always applied correctly on home dashboard (#737)
This commit is contained in:
parent
89cae90f29
commit
aee92c620e
9 changed files with 685 additions and 231 deletions
|
@ -7,6 +7,7 @@
|
|||
* When searching for pages, if filter text is empty space, query returns only pages where title contains empty spaces (#746)
|
||||
* Regression. Text is not always set when creating a lot of text blocks (#741)
|
||||
* Respective theme colors should differ for text color and background colors in action menu (#738)
|
||||
* Inconsistent DND-behavior on dashboard due to incorrect drop-target position calculation (#657)
|
||||
* Fix app configuration lifetime (#735)
|
||||
* Avatar image is not displayed after registration started after logout (#692)
|
||||
* Editor business logic (event detection for backspace and enter press, checkbox button click detection, etc.) is broken for text blocks, whose style was changed via `turn-into-toolbar` in `multi-select` mode after returning to `edit` mode (#514)
|
||||
|
|
|
@ -124,5 +124,5 @@ class DashboardAdapter(
|
|||
return true
|
||||
}
|
||||
|
||||
fun provideAdapterData() = data.toList()
|
||||
fun provideAdapterData(): List<DashboardView> = data.toList()
|
||||
}
|
|
@ -57,7 +57,7 @@ class HomeDashboardFragment : ViewStateFragment<State>(R.layout.fragment_desktop
|
|||
.onItemMove(from, to)
|
||||
.also {
|
||||
vm.onItemMoved(
|
||||
alteredViews = dashboardAdapter.provideAdapterData(),
|
||||
views = dashboardAdapter.provideAdapterData(),
|
||||
from = from,
|
||||
to = to
|
||||
)
|
||||
|
|
|
@ -3,8 +3,11 @@ package com.agileburo.anytype.presentation.desktop
|
|||
import com.agileburo.anytype.domain.common.Id
|
||||
|
||||
sealed class DashboardView {
|
||||
|
||||
abstract val id: Id
|
||||
|
||||
data class Document(
|
||||
val id: Id,
|
||||
override val id: Id,
|
||||
val target: Id,
|
||||
val title: String? = null,
|
||||
val emoji: String? = null,
|
||||
|
|
|
@ -73,7 +73,7 @@ class HomeDashboardViewModel(
|
|||
private fun startInterceptingEvents(context: String) {
|
||||
interceptEvents
|
||||
.build(InterceptEvents.Params(context = context))
|
||||
.onEach { Timber.d("New events: $it") }
|
||||
.onEach { Timber.d("New events on home dashboard: $it") }
|
||||
.onEach { events -> processEvents(events) }
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
@ -170,30 +170,31 @@ class HomeDashboardViewModel(
|
|||
}
|
||||
|
||||
/**
|
||||
* @param alteredViews set of views in order altered by a block dragging action
|
||||
* @param views set of views in order altered by a block dragging action
|
||||
* @param from position of the block being dragged
|
||||
* @param to target position
|
||||
*/
|
||||
fun onItemMoved(
|
||||
alteredViews: List<DashboardView>,
|
||||
views: List<DashboardView>,
|
||||
from: Int,
|
||||
to: Int
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
val direction = if (from < to) Position.BOTTOM else Position.TOP
|
||||
val subject = views[to].id
|
||||
val target = if (direction == Position.TOP) views[to.inc()].id else views[to.dec()].id
|
||||
movementChannel.send(
|
||||
Movement(
|
||||
direction = if (from < to) Position.BOTTOM else Position.TOP,
|
||||
subject = (alteredViews[to] as DashboardView.Document).id,
|
||||
target = (alteredViews[from] as DashboardView.Document).id
|
||||
direction = direction,
|
||||
subject = subject,
|
||||
target = target
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onItemDropped(view: DashboardView) {
|
||||
viewModelScope.launch {
|
||||
dropChannel.send((view as DashboardView.Document).id)
|
||||
}
|
||||
viewModelScope.launch { dropChannel.send(view.id) }
|
||||
}
|
||||
|
||||
private fun proceedWithOpeningDocument(id: String) {
|
||||
|
|
|
@ -188,8 +188,9 @@ fun Block.Content.Text.marks(): List<Markup.Mark> = marks.mapNotNull { mark ->
|
|||
}
|
||||
}
|
||||
|
||||
fun HomeDashboard.toView(builder: UrlBuilder): List<DashboardView.Document> =
|
||||
children.mapNotNull { id ->
|
||||
fun HomeDashboard.toView(
|
||||
builder: UrlBuilder
|
||||
): List<DashboardView.Document> = children.mapNotNull { id ->
|
||||
blocks.find { block -> block.id == id }?.let { model ->
|
||||
when (val content = model.content) {
|
||||
is Block.Content.Link -> {
|
||||
|
|
|
@ -0,0 +1,522 @@
|
|||
package com.agileburo.anytype.presentation.home
|
||||
|
||||
import MockDataFactory
|
||||
import com.agileburo.anytype.core_utils.ext.shift
|
||||
import com.agileburo.anytype.domain.base.Either
|
||||
import com.agileburo.anytype.domain.block.interactor.Move
|
||||
import com.agileburo.anytype.domain.block.model.Block
|
||||
import com.agileburo.anytype.domain.block.model.Position
|
||||
import com.agileburo.anytype.domain.dashboard.interactor.toHomeDashboard
|
||||
import com.agileburo.anytype.domain.dashboard.model.HomeDashboard
|
||||
import com.agileburo.anytype.domain.event.interactor.InterceptEvents
|
||||
import com.agileburo.anytype.domain.event.model.Event
|
||||
import com.agileburo.anytype.domain.event.model.Payload
|
||||
import com.agileburo.anytype.presentation.desktop.HomeDashboardStateMachine
|
||||
import com.agileburo.anytype.presentation.mapper.toView
|
||||
import com.jraska.livedata.test
|
||||
import com.nhaarman.mockitokotlin2.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
class DashboardDragAndDropTest : DashboardTestSetup() {
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `block dragging events do not alter overall state`() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val pages = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
target = MockDataFactory.randomUuid(),
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString(),
|
||||
"icon" to MockDataFactory.randomString()
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
target = MockDataFactory.randomUuid(),
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val dashboard = Block(
|
||||
id = config.home,
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.HOME
|
||||
),
|
||||
children = pages.map { page -> page.id },
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
val delayInMillis = 100L
|
||||
|
||||
val events = flow {
|
||||
delay(delayInMillis)
|
||||
emit(
|
||||
listOf(
|
||||
Event.Command.ShowBlock(
|
||||
root = config.home,
|
||||
context = config.home,
|
||||
blocks = listOf(dashboard) + pages
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
stubGetConfig(
|
||||
Either.Right(config)
|
||||
)
|
||||
|
||||
stubObserveEvents(
|
||||
params = InterceptEvents.Params(context = config.home),
|
||||
flow = events
|
||||
)
|
||||
|
||||
stubOpenDashboard(
|
||||
payload = Payload(
|
||||
context = config.home,
|
||||
events = emptyList()
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
vm = buildViewModel()
|
||||
|
||||
vm.onViewCreated()
|
||||
|
||||
coroutineTestRule.advanceTime(delayInMillis)
|
||||
|
||||
val expected = HomeDashboardStateMachine.State(
|
||||
isLoading = false,
|
||||
isInitialzed = true,
|
||||
dashboard = listOf(
|
||||
dashboard,
|
||||
pages.first(),
|
||||
pages.last()
|
||||
).toHomeDashboard(dashboard.id),
|
||||
error = null
|
||||
)
|
||||
|
||||
val views = runBlocking {
|
||||
listOf(
|
||||
dashboard,
|
||||
pages.first(),
|
||||
pages.last()
|
||||
).toHomeDashboard(dashboard.id).toView(builder)
|
||||
}
|
||||
|
||||
val from = 0
|
||||
val to = 1
|
||||
|
||||
vm.state.test().assertValue(expected)
|
||||
|
||||
vm.onItemMoved(
|
||||
from = from,
|
||||
to = to,
|
||||
views = views.toMutableList().shift(from, to)
|
||||
)
|
||||
|
||||
verifyZeroInteractions(move)
|
||||
vm.state.test().assertValue(expected)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should start dispatching drag-and-drop actions when the dragged item is dropped`() {
|
||||
|
||||
val pages = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
target = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString()
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
target = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString(),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val dashboard = HomeDashboard(
|
||||
id = config.home,
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
type = Block.Content.Smart.Type.HOME,
|
||||
blocks = pages,
|
||||
children = pages.map { it.id }
|
||||
)
|
||||
|
||||
val delayInMillis = 100L
|
||||
|
||||
stubGetConfig(Either.Right(config))
|
||||
stubObserveEvents(params = InterceptEvents.Params(context = config.home))
|
||||
stubOpenDashboard()
|
||||
|
||||
vm = buildViewModel()
|
||||
|
||||
vm.onViewCreated()
|
||||
|
||||
coroutineTestRule.advanceTime(delayInMillis)
|
||||
|
||||
val views = runBlocking {
|
||||
dashboard.toView(builder)
|
||||
}
|
||||
|
||||
val from = 0
|
||||
val to = 1
|
||||
|
||||
vm.onItemMoved(
|
||||
from = from,
|
||||
to = to,
|
||||
views = views.toMutableList().shift(from, to)
|
||||
)
|
||||
|
||||
vm.onItemDropped(views[from])
|
||||
|
||||
verify(move, times(1)).invoke(
|
||||
scope = any(),
|
||||
params = eq(
|
||||
Move.Params(
|
||||
context = config.home,
|
||||
targetContext = config.home,
|
||||
targetId = pages.last().id,
|
||||
blockIds = listOf(pages.first().id),
|
||||
position = Position.BOTTOM
|
||||
)
|
||||
),
|
||||
onResult = any()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should call move use-case for dropping the last block before the first block`() {
|
||||
|
||||
val links = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
target = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString()
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
target = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString(),
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
target = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString(),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val dashboard = HomeDashboard(
|
||||
id = config.home,
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
type = Block.Content.Smart.Type.HOME,
|
||||
blocks = links,
|
||||
children = links.map { it.id }
|
||||
)
|
||||
|
||||
val delayInMillis = 100L
|
||||
|
||||
stubGetConfig(Either.Right(config))
|
||||
stubObserveEvents(params = InterceptEvents.Params(context = config.home))
|
||||
stubOpenDashboard()
|
||||
|
||||
vm = buildViewModel()
|
||||
|
||||
vm.onViewCreated()
|
||||
|
||||
coroutineTestRule.advanceTime(delayInMillis)
|
||||
|
||||
val views = runBlocking { dashboard.toView(builder) }
|
||||
|
||||
val from = 2
|
||||
val to = 0
|
||||
|
||||
vm.onItemMoved(
|
||||
from = from,
|
||||
to = to,
|
||||
views = views.toMutableList().shift(from, to)
|
||||
)
|
||||
|
||||
vm.onItemDropped(views[from])
|
||||
|
||||
verify(move, times(1)).invoke(
|
||||
scope = any(),
|
||||
params = eq(
|
||||
Move.Params(
|
||||
context = config.home,
|
||||
targetContext = config.home,
|
||||
targetId = links.first().id,
|
||||
blockIds = listOf(links.last().id),
|
||||
position = Position.TOP
|
||||
)
|
||||
),
|
||||
onResult = any()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should call move use-case for dropping the first block after the second block`() {
|
||||
|
||||
val links = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
target = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString()
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
target = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString(),
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
target = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString(),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val dashboard = HomeDashboard(
|
||||
id = config.home,
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
type = Block.Content.Smart.Type.HOME,
|
||||
blocks = links,
|
||||
children = links.map { it.id }
|
||||
)
|
||||
|
||||
val delayInMillis = 100L
|
||||
|
||||
stubGetConfig(Either.Right(config))
|
||||
stubObserveEvents(params = InterceptEvents.Params(context = config.home))
|
||||
stubOpenDashboard()
|
||||
|
||||
vm = buildViewModel()
|
||||
|
||||
vm.onViewCreated()
|
||||
|
||||
coroutineTestRule.advanceTime(delayInMillis)
|
||||
|
||||
val views = runBlocking { dashboard.toView(builder) }
|
||||
|
||||
val from = 0
|
||||
val to = 1
|
||||
|
||||
vm.onItemMoved(
|
||||
from = from,
|
||||
to = to,
|
||||
views = views.toMutableList().shift(from, to)
|
||||
)
|
||||
|
||||
vm.onItemDropped(views[from])
|
||||
|
||||
verify(move, times(1)).invoke(
|
||||
scope = any(),
|
||||
params = eq(
|
||||
Move.Params(
|
||||
context = config.home,
|
||||
targetContext = config.home,
|
||||
targetId = links[1].id,
|
||||
blockIds = listOf(links.first().id),
|
||||
position = Position.BOTTOM
|
||||
)
|
||||
),
|
||||
onResult = any()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should call move use-case for dropping the first block after the third block`() {
|
||||
|
||||
val links = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
target = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString()
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
target = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString(),
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
content = Block.Content.Link(
|
||||
type = Block.Content.Link.Type.PAGE,
|
||||
target = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(
|
||||
map = mapOf(
|
||||
"name" to MockDataFactory.randomString(),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val dashboard = HomeDashboard(
|
||||
id = config.home,
|
||||
fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
type = Block.Content.Smart.Type.HOME,
|
||||
blocks = links,
|
||||
children = links.map { it.id }
|
||||
)
|
||||
|
||||
val delayInMillis = 100L
|
||||
|
||||
stubGetConfig(Either.Right(config))
|
||||
stubObserveEvents(params = InterceptEvents.Params(context = config.home))
|
||||
stubOpenDashboard()
|
||||
|
||||
vm = buildViewModel()
|
||||
|
||||
vm.onViewCreated()
|
||||
|
||||
coroutineTestRule.advanceTime(delayInMillis)
|
||||
|
||||
val views = runBlocking { dashboard.toView(builder) }
|
||||
|
||||
val from = 0
|
||||
val to = 2
|
||||
|
||||
vm.onItemMoved(
|
||||
from = from,
|
||||
to = to,
|
||||
views = views.toMutableList().shift(from, to)
|
||||
)
|
||||
|
||||
vm.onItemDropped(views[from])
|
||||
|
||||
verify(move, times(1)).invoke(
|
||||
scope = any(),
|
||||
params = eq(
|
||||
Move.Params(
|
||||
context = config.home,
|
||||
targetContext = config.home,
|
||||
targetId = links.last().id,
|
||||
blockIds = listOf(links.first().id),
|
||||
position = Position.BOTTOM
|
||||
)
|
||||
),
|
||||
onResult = any()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package com.agileburo.anytype.presentation.home
|
||||
|
||||
import MockDataFactory
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import com.agileburo.anytype.domain.auth.interactor.GetCurrentAccount
|
||||
import com.agileburo.anytype.domain.auth.model.Account
|
||||
import com.agileburo.anytype.domain.base.Either
|
||||
import com.agileburo.anytype.domain.block.interactor.Move
|
||||
import com.agileburo.anytype.domain.config.*
|
||||
import com.agileburo.anytype.domain.dashboard.interactor.CloseDashboard
|
||||
import com.agileburo.anytype.domain.dashboard.interactor.OpenDashboard
|
||||
import com.agileburo.anytype.domain.event.interactor.InterceptEvents
|
||||
import com.agileburo.anytype.domain.event.model.Event
|
||||
import com.agileburo.anytype.domain.event.model.Payload
|
||||
import com.agileburo.anytype.domain.misc.UrlBuilder
|
||||
import com.agileburo.anytype.domain.page.CreatePage
|
||||
import com.agileburo.anytype.presentation.desktop.HomeDashboardEventConverter
|
||||
import com.agileburo.anytype.presentation.desktop.HomeDashboardViewModel
|
||||
import com.agileburo.anytype.presentation.util.CoroutinesTestRule
|
||||
import com.nhaarman.mockitokotlin2.any
|
||||
import com.nhaarman.mockitokotlin2.doAnswer
|
||||
import com.nhaarman.mockitokotlin2.doReturn
|
||||
import com.nhaarman.mockitokotlin2.stub
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.junit.Rule
|
||||
import org.mockito.Mock
|
||||
|
||||
open class DashboardTestSetup {
|
||||
|
||||
@get:Rule
|
||||
val rule = InstantTaskExecutorRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
@Mock
|
||||
lateinit var getCurrentAccount: GetCurrentAccount
|
||||
|
||||
@Mock
|
||||
lateinit var openDashboard: OpenDashboard
|
||||
|
||||
@Mock
|
||||
lateinit var getConfig: GetConfig
|
||||
|
||||
@Mock
|
||||
lateinit var closeDashboard: CloseDashboard
|
||||
|
||||
@Mock
|
||||
lateinit var createPage: CreatePage
|
||||
|
||||
@Mock
|
||||
lateinit var interceptEvents: InterceptEvents
|
||||
|
||||
@Mock
|
||||
lateinit var getDebugSettings: GetDebugSettings
|
||||
|
||||
@Mock
|
||||
lateinit var move: Move
|
||||
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
|
||||
lateinit var vm: HomeDashboardViewModel
|
||||
|
||||
val builder: UrlBuilder get() = UrlBuilder(gateway)
|
||||
|
||||
val config = Config(
|
||||
home = MockDataFactory.randomUuid(),
|
||||
gateway = MockDataFactory.randomUuid(),
|
||||
profile = MockDataFactory.randomUuid()
|
||||
)
|
||||
|
||||
fun buildViewModel() = HomeDashboardViewModel(
|
||||
getCurrentAccount = getCurrentAccount,
|
||||
openDashboard = openDashboard,
|
||||
closeDashboard = closeDashboard,
|
||||
createPage = createPage,
|
||||
getConfig = getConfig,
|
||||
move = move,
|
||||
interceptEvents = interceptEvents,
|
||||
eventConverter = HomeDashboardEventConverter.DefaultConverter(),
|
||||
getDebugSettings = getDebugSettings
|
||||
)
|
||||
|
||||
fun stubGetConfig(response: Either.Right<Config>) {
|
||||
getConfig.stub {
|
||||
onBlocking { invoke(any(), any(), any()) } doAnswer { answer ->
|
||||
answer.getArgument<(Either<Throwable, Config>) -> Unit>(2)(response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun stubObserveEvents(
|
||||
flow: Flow<List<Event>> = flowOf(),
|
||||
params: InterceptEvents.Params? = null
|
||||
) {
|
||||
interceptEvents.stub {
|
||||
onBlocking { build(params) } doReturn flow
|
||||
}
|
||||
}
|
||||
|
||||
fun stubOpenDashboard(
|
||||
payload: Payload = Payload(
|
||||
context = MockDataFactory.randomString(),
|
||||
events = emptyList()
|
||||
)
|
||||
) {
|
||||
openDashboard.stub {
|
||||
onBlocking { invoke(params = null) } doReturn Either.Right(payload)
|
||||
}
|
||||
}
|
||||
|
||||
fun stubCreatePage(id: String) {
|
||||
createPage.stub {
|
||||
onBlocking { invoke(any(), any(), any()) } doAnswer { answer ->
|
||||
answer.getArgument<(Either<Throwable, String>) -> Unit>(2)(Either.Right(id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun stubCloseDashboard() {
|
||||
closeDashboard.stub {
|
||||
onBlocking { invoke(any(), any(), any()) } doAnswer { answer ->
|
||||
answer.getArgument<(Either<Throwable, Unit>) -> Unit>(2)(Either.Right(Unit))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun stubGetEditorSettings() {
|
||||
getDebugSettings.stub {
|
||||
onBlocking { invoke(any()) } doReturn Either.Right(DebugSettings(true))
|
||||
}
|
||||
}
|
||||
|
||||
fun stubGetCurrentAccount(accountResponse: Either.Right<Account>) {
|
||||
getCurrentAccount.stub {
|
||||
onBlocking { invoke(any(), any(), any()) } doAnswer { answer ->
|
||||
answer.getArgument<(Either<Throwable, Account>) -> Unit>(2)(accountResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -246,223 +246,6 @@ class HomeDashboardViewModelTest {
|
|||
)
|
||||
}
|
||||
|
||||
//Todo Broken after https://github.com/anytypeio/android-anytype/pull/549
|
||||
// @Test
|
||||
// fun `block dragging events do not alter overall state`() {
|
||||
//
|
||||
// // SETUP
|
||||
//
|
||||
// val emoji = Emoji(
|
||||
// unicode = MockDataFactory.randomString(),
|
||||
// alias = MockDataFactory.randomString()
|
||||
// )
|
||||
//
|
||||
// val pages = listOf(
|
||||
// Block(
|
||||
// id = MockDataFactory.randomUuid(),
|
||||
// children = emptyList(),
|
||||
// fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
// content = Block.Content.Link(
|
||||
// target = MockDataFactory.randomUuid(),
|
||||
// type = Block.Content.Link.Type.PAGE,
|
||||
// fields = Block.Fields(
|
||||
// map = mapOf(
|
||||
// "name" to MockDataFactory.randomString(),
|
||||
// "icon" to MockDataFactory.randomString()
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// ),
|
||||
// Block(
|
||||
// id = MockDataFactory.randomUuid(),
|
||||
// children = emptyList(),
|
||||
// fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
// content = Block.Content.Link(
|
||||
// target = MockDataFactory.randomUuid(),
|
||||
// type = Block.Content.Link.Type.PAGE,
|
||||
// fields = Block.Fields(
|
||||
// map = mapOf(
|
||||
// "name" to MockDataFactory.randomString(),
|
||||
// "icon" to emoji.name
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
//
|
||||
// val dashboard = Block(
|
||||
// id = config.home,
|
||||
// content = Block.Content.Smart(
|
||||
// type = Block.Content.Smart.Type.HOME
|
||||
// ),
|
||||
// children = pages.map { page -> page.id },
|
||||
// fields = Block.Fields.empty()
|
||||
// )
|
||||
//
|
||||
// val delayInMillis = 100L
|
||||
//
|
||||
// val events = flow {
|
||||
// delay(delayInMillis)
|
||||
// emit(
|
||||
// listOf(
|
||||
// Event.Command.ShowBlock(
|
||||
// root = config.home,
|
||||
// context = config.home,
|
||||
// blocks = listOf(dashboard) + pages
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// stubGetConfig(
|
||||
// Either.Right(config)
|
||||
// )
|
||||
//
|
||||
// stubObserveEvents(
|
||||
// params = InterceptEvents.Params(context = config.home),
|
||||
// flow = events
|
||||
// )
|
||||
//
|
||||
// stubOpenDashboard(
|
||||
// payload = Payload(
|
||||
// context = config.home,
|
||||
// events = emptyList()
|
||||
// )
|
||||
// )
|
||||
//
|
||||
// // TESTING
|
||||
//
|
||||
// vm = buildViewModel()
|
||||
//
|
||||
// vm.onViewCreated()
|
||||
//
|
||||
// coroutineTestRule.advanceTime(delayInMillis)
|
||||
//
|
||||
// val expected = HomeDashboardStateMachine.State(
|
||||
// isLoading = false,
|
||||
// isInitialzed = true,
|
||||
// dashboard = listOf(
|
||||
// dashboard,
|
||||
// pages.first(),
|
||||
// pages.last()
|
||||
// ).toHomeDashboard(dashboard.id),
|
||||
// error = null
|
||||
// )
|
||||
//
|
||||
// val views = runBlocking {
|
||||
// listOf(
|
||||
// dashboard,
|
||||
// pages.first(),
|
||||
// pages.last()
|
||||
// ).toHomeDashboard(dashboard.id).toView(builder)
|
||||
// }
|
||||
//
|
||||
// val from = 0
|
||||
// val to = 1
|
||||
//
|
||||
// vm.state.test().assertValue(expected)
|
||||
//
|
||||
// vm.onItemMoved(
|
||||
// from = from,
|
||||
// to = to,
|
||||
// alteredViews = views.toMutableList().shift(from, to)
|
||||
// )
|
||||
//
|
||||
// verifyZeroInteractions(dnd)
|
||||
// vm.state.test().assertValue(expected)
|
||||
// }
|
||||
|
||||
// @Test
|
||||
// fun `should start dispatching drag-and-drop actions when the dragged item is dropped`() {
|
||||
//
|
||||
// val emoji = Emoji(
|
||||
// unicode = MockDataFactory.randomString(),
|
||||
// alias = MockDataFactory.randomString()
|
||||
// )
|
||||
//
|
||||
// val pages = listOf(
|
||||
// Block(
|
||||
// id = MockDataFactory.randomUuid(),
|
||||
// children = emptyList(),
|
||||
// fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
// content = Block.Content.Link(
|
||||
// type = Block.Content.Link.Type.PAGE,
|
||||
// target = MockDataFactory.randomUuid(),
|
||||
// fields = Block.Fields(
|
||||
// map = mapOf(
|
||||
// "name" to MockDataFactory.randomString(),
|
||||
// "icon" to emoji.name
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// ),
|
||||
// Block(
|
||||
// id = MockDataFactory.randomUuid(),
|
||||
// children = emptyList(),
|
||||
// fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
// content = Block.Content.Link(
|
||||
// type = Block.Content.Link.Type.PAGE,
|
||||
// target = MockDataFactory.randomUuid(),
|
||||
// fields = Block.Fields(
|
||||
// map = mapOf(
|
||||
// "name" to MockDataFactory.randomString(),
|
||||
// "icon" to emoji.name
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
//
|
||||
// val dashboard = HomeDashboard(
|
||||
// id = config.home,
|
||||
// fields = Block.Fields(map = mapOf("name" to MockDataFactory.randomString())),
|
||||
// type = Block.Content.Smart.Type.HOME,
|
||||
// blocks = pages,
|
||||
// children = pages.map { it.id }
|
||||
// )
|
||||
//
|
||||
// val delayInMillis = 100L
|
||||
//
|
||||
// stubGetConfig(Either.Right(config))
|
||||
// stubObserveEvents(params = InterceptEvents.Params(context = config.home))
|
||||
// stubOpenDashboard()
|
||||
//
|
||||
// vm = buildViewModel()
|
||||
//
|
||||
// vm.onViewCreated()
|
||||
//
|
||||
// coroutineTestRule.advanceTime(delayInMillis)
|
||||
//
|
||||
// val views = runBlocking {
|
||||
// dashboard.toView(builder)
|
||||
// }
|
||||
//
|
||||
// val from = 0
|
||||
// val to = 1
|
||||
//
|
||||
// vm.onItemMoved(
|
||||
// from = from,
|
||||
// to = to,
|
||||
// alteredViews = views.toMutableList().shift(from, to)
|
||||
// )
|
||||
//
|
||||
// vm.onItemDropped(views[from])
|
||||
//
|
||||
// verify(dnd, times(1)).invoke(
|
||||
// scope = any(),
|
||||
// params = eq(
|
||||
// DragAndDrop.Params(
|
||||
// context = config.home,
|
||||
// targetContext = config.home,
|
||||
// targetId = pages.last().id,
|
||||
// blockIds = listOf(pages.first().id),
|
||||
// position = Position.BOTTOM
|
||||
// )
|
||||
// ),
|
||||
// onResult = any()
|
||||
// )
|
||||
// }
|
||||
|
||||
@Test
|
||||
fun `should proceed with getting account and opening dashboard when view is created`() {
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue