Auto commit Fri Mar 20 11:01:01 PM CDT 2026

This commit is contained in:
Tretzi
2026-03-20 23:01:02 -05:00
parent e2cd1ff4df
commit e84ab89856
6 changed files with 959 additions and 0 deletions

View File

@@ -0,0 +1,167 @@
package com.mindmachine.mvp.session
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.test.swipeLeft
import androidx.compose.ui.test.swipeUp
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
/**
* Compose UI tests for TimelineEditorScreen gesture handling.
* These tests run without a physical device using Compose testing framework.
*/
@OptIn(ExperimentalTestApi::class)
@RunWith(AndroidJUnit4::class)
class TimelineEditorGestureTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun timelineGraph_renders_without_crashing() {
composeTestRule.setContent {
// Create a minimal test state
var state by remember { mutableStateOf(TimelineEditorState.default()) }
TimelineGraph(
title = "Visual",
leftLabel = "Flash Interval",
rightLabel = "Blank Interval",
curveLeft = state.visualLeft,
curveRight = state.visualRight,
activeCurve = state.activeCurve,
viewport = state.viewport,
selection = state.selection,
playheadSec = state.playheadSec,
onViewportChanged = { state = state.copy(viewport = it) },
onSelectionChanged = { sel -> state = state.copy(selection = sel).clampSelection() },
onUpdateCurve = { curveId, newCurve -> state = state.withCurve(curveId, newCurve) },
onTapSideSelect = { side ->
state = state.copy(activeCurve = if (side == Side.LEFT) TimelineEditorState.ActiveCurve.VISUAL_LEFT else TimelineEditorState.ActiveCurve.VISUAL_RIGHT)
}
)
}
// Basic sanity check that the graph renders
composeTestRule.waitForIdle()
}
@Test
fun single_finger_vertical_swipe_does_not_crash() {
composeTestRule.setContent {
var state by remember { mutableStateOf(TimelineEditorState.default()) }
TimelineGraph(
title = "Visual",
leftLabel = "Flash Interval",
rightLabel = "Blank Interval",
curveLeft = state.visualLeft,
curveRight = state.visualRight,
activeCurve = state.activeCurve,
viewport = state.viewport,
selection = state.selection,
playheadSec = state.playheadSec,
onViewportChanged = { state = state.copy(viewport = it) },
onSelectionChanged = { sel -> state = state.copy(selection = sel).clampSelection() },
onUpdateCurve = { curveId, newCurve -> state = state.withCurve(curveId, newCurve) },
onTapSideSelect = { side ->
state = state.copy(activeCurve = if (side == Side.LEFT) TimelineEditorState.ActiveCurve.VISUAL_LEFT else TimelineEditorState.ActiveCurve.VISUAL_RIGHT)
}
)
}
composeTestRule.waitForIdle()
// Perform vertical swipe (used for dragging points)
composeTestRule.onNodeWithTag("timeline_graph")
.performTouchInput {
swipeUp(startY = 150f, endY = 50f)
}
composeTestRule.waitForIdle()
}
@Test
fun single_finger_horizontal_swipe_does_not_crash() {
composeTestRule.setContent {
var state by remember { mutableStateOf(TimelineEditorState.default()) }
TimelineGraph(
title = "Visual",
leftLabel = "Flash Interval",
rightLabel = "Blank Interval",
curveLeft = state.visualLeft,
curveRight = state.visualRight,
activeCurve = state.activeCurve,
viewport = state.viewport,
selection = state.selection,
playheadSec = state.playheadSec,
onViewportChanged = { state = state.copy(viewport = it) },
onSelectionChanged = { sel -> state = state.copy(selection = sel).clampSelection() },
onUpdateCurve = { curveId, newCurve -> state = state.withCurve(curveId, newCurve) },
onTapSideSelect = { side ->
state = state.copy(activeCurve = if (side == Side.LEFT) TimelineEditorState.ActiveCurve.VISUAL_LEFT else TimelineEditorState.ActiveCurve.VISUAL_RIGHT)
}
)
}
composeTestRule.waitForIdle()
// Perform horizontal swipe (panning)
composeTestRule.onNodeWithTag("timeline_graph")
.performTouchInput {
swipeLeft(startX = 250f, endX = 150f)
}
composeTestRule.waitForIdle()
}
@Test
fun multi_touch_gesture_does_not_crash() {
composeTestRule.setContent {
var state by remember { mutableStateOf(TimelineEditorState.default()) }
TimelineGraph(
title = "Visual",
leftLabel = "Flash Interval",
rightLabel = "Blank Interval",
curveLeft = state.visualLeft,
curveRight = state.visualRight,
activeCurve = state.activeCurve,
viewport = state.viewport,
selection = state.selection,
playheadSec = state.playheadSec,
onViewportChanged = { state = state.copy(viewport = it) },
onSelectionChanged = { sel -> state = state.copy(selection = sel).clampSelection() },
onUpdateCurve = { curveId, newCurve -> state = state.withCurve(curveId, newCurve) },
onTapSideSelect = { side ->
state = state.copy(activeCurve = if (side == Side.LEFT) TimelineEditorState.ActiveCurve.VISUAL_LEFT else TimelineEditorState.ActiveCurve.VISUAL_RIGHT)
}
)
}
composeTestRule.waitForIdle()
// Simulate multi-touch gesture (two fingers)
composeTestRule.onNodeWithTag("timeline_graph")
.performTouchInput {
down(0, androidx.compose.ui.geometry.Offset(100f, 100f))
down(1, androidx.compose.ui.geometry.Offset(200f, 100f))
moveTo(0, androidx.compose.ui.geometry.Offset(150f, 100f))
moveTo(1, androidx.compose.ui.geometry.Offset(250f, 100f))
up(0)
up(1)
}
composeTestRule.waitForIdle()
}
}