| name | trail-sense-android-tests |
| description | Add Trail Sense UI automation tests using AutomationLibrary and ToolTestBase for tool workflows or androidTests. |
Trail Sense Android Tests
Create UI automation tests for Trail Sense tools using AutomationLibrary and ToolTestBase.
Test Structure
package com.kylecorry.trail_sense.tools.<toolname>
import com.kylecorry.trail_sense.R
import com.kylecorry.trail_sense.test_utils.AutomationLibrary.*
import com.kylecorry.trail_sense.test_utils.TestUtils
import com.kylecorry.trail_sense.test_utils.TestUtils.back
import com.kylecorry.trail_sense.test_utils.TestUtils.clickListItemMenu
import com.kylecorry.trail_sense.test_utils.ToolTestBase
import com.kylecorry.trail_sense.test_utils.views.*
import com.kylecorry.trail_sense.tools.tools.infrastructure.Tools
import org.junit.Test
class Tool<Name>Test : ToolTestBase(Tools.<TOOL_ID>) {
@Test
fun verifyBasicFunctionality() {
hasText(R.id.title, string(R.string.tool_title))
canCreateItem()
canEditItem()
canDeleteItem()
verifyQuickAction()
}
private fun canCreateItem() { }
private fun canEditItem() { }
private fun canDeleteItem() { }
private fun verifyQuickAction() { }
}
Location: app/src/androidTest/java/com/kylecorry/trail_sense/tools/<toolname>/Tool<Name>Test.kt
Workflow
- Inspect the target tool and nearby
Tool*Test.kt files. This step is complete when the tool id, package, primary screen title, and existing test patterns are known.
- Add or update the test class under the location above. This step is complete when the test covers the requested workflow and uses stable selectors from the strategy below.
- Run a focused emulator integration test when an emulator is available. This step is complete when the requested test passes or the blocking reason is reported.
Selection Strategy: Text Over IDs
Prefer text-based selection for most interactions. Use IDs only when necessary.
Use Text For
click(string(R.string.distance))
click(string(R.string.delete))
click("High")
click("Test Group")
hasText(string(R.string.no_paths))
hasText("Test Path")
input(string(R.string.name), "My Item")
input(string(R.string.distance), "1.0")
isChecked(string(R.string.tide_clock))
Use IDs Only For
hasText(R.id.paths_title, string(R.string.paths))
hasText(R.id.tide_title, "Tide 1")
click(R.id.add_btn)
click(R.id.play_btn)
input(R.id.searchbox, "query")
input(R.id.tide_name, "Tide 1")
input(R.id.utm, "42, -72")
hasText(R.id.result, "3.2808 ft")
hasText(R.id.total_percent_packed, "50% packed")
isVisible(R.id.chart)
scrollToEnd(R.id.scroll_view)
click(toolbarButton(R.id.paths_title, Side.Right))
Andromeda List Item IDs
List items use Andromeda library IDs:
click(com.kylecorry.andromeda.views.R.id.title)
hasText(com.kylecorry.andromeda.views.R.id.title, "Item Name")
hasText(com.kylecorry.andromeda.views.R.id.description, "Details")
click(com.kylecorry.andromeda.views.R.id.checkbox)
click(com.kylecorry.andromeda.views.R.id.trailing_icon_btn)
click(com.kylecorry.andromeda.views.R.id.menu_btn)
Common Patterns
Create/Edit/Delete Flow
private fun canCreateItem() {
click(R.id.add_btn)
click(string(R.string.new_item))
input(string(R.string.name), "Test Item")
clickOk()
hasText("Test Item")
}
private fun canEditItem() {
clickListItemMenu(string(R.string.edit))
input("Test Item", "Test Item 2")
clickOk()
hasText("Test Item 2")
}
private fun canDeleteItem() {
clickListItemMenu(string(R.string.delete))
clickOk()
not { hasText("Test Item 2", waitForTime = 0) }
}
Toolbar Menu
click(toolbarButton(R.id.title, Side.Right))
click(string(R.string.export))
Quick Actions
private fun verifyQuickAction() {
TestUtils.openQuickActions()
click(quickAction(Tools.QUICK_ACTION_ID))
TestUtils.closeQuickActions()
}
Optional Elements
optional {
hasText(string(R.string.disclaimer))
clickOk()
}
Navigate Back
backUntil { isVisible(R.id.paths_title, waitForTime = 1000) }
Key Functions
| Function | Usage |
|---|
click(text) | Click by text (contains match) |
click(text, exact = true) | Click by exact text |
click(R.id.x) | Click by ID |
hasText(text) | Verify text on screen |
hasText(R.id.x, text) | Verify text in view |
hasText(R.id.x, Regex(...)) | Verify regex pattern |
input(R.id.x, text) | Enter text by ID |
input(label, text) | Enter text by label |
clickOk() | Click OK in dialogs |
clickListItemMenu(label) | Click list item overflow menu |
optional { } | Ignore failures |
not { } | Assert action fails |
string(R.string.x) | Get string resource |
scrollUntil { } | Scroll until condition |
backUntil { } | Press back until condition |
Running Tests
./scripts/run-emulator-integration-tests.sh
./scripts/run-emulator-integration-tests.sh com.kylecorry.trail_sense.tools.notes.ToolNotesTest 180
The script defaults to a 1800 second timeout. Most individual integration tests should finish in 60 to 180 seconds, so pass a shorter timeout for focused runs when practical.
Source Files
For complete API details and additional functions, read:
app/src/androidTest/java/com/kylecorry/trail_sense/test_utils/AutomationLibrary.kt
app/src/androidTest/java/com/kylecorry/trail_sense/test_utils/TestUtils.kt
app/src/androidTest/java/com/kylecorry/trail_sense/test_utils/views/
For example tests, see existing tool tests in:
app/src/androidTest/java/com/kylecorry/trail_sense/tools/*/Tool*Test.kt