# Trail Sense Android Tests

> Add Trail Sense UI automation tests using AutomationLibrary and ToolTestBase for tool workflows or androidTests.

- Skill: `kylecorry31/trail-sense-android-tests` (Agent Skill)
- Install (CLI): `npx skillmds@latest add kylecorry31/trail-sense-android-tests`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kylecorry31/trail-sense-android-tests/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: kylecorry31 (https://skillmd.com/u/kylecorry31)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kylecorry31/trail-sense-android-tests

---


# Trail Sense Android Tests

Create UI automation tests for Trail Sense tools using `AutomationLibrary` and `ToolTestBase`.

## Test Structure

```kotlin
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

1. 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.
2. 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.
3. 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

```kotlin
// Clicking tabs, buttons, menu items, options
click(string(R.string.distance))
click(string(R.string.delete))
click("High")
click("Test Group")

// Verifying text anywhere on screen
hasText(string(R.string.no_paths))
hasText("Test Path")

// Dialog inputs (by label/hint)
input(string(R.string.name), "My Item")
input(string(R.string.distance), "1.0")

// Checkbox state by label
isChecked(string(R.string.tide_clock))
```

### Use IDs Only For

```kotlin
// Title bars (for verification)
hasText(R.id.paths_title, string(R.string.paths))
hasText(R.id.tide_title, "Tide 1")

// Add/play buttons (no text label)
click(R.id.add_btn)
click(R.id.play_btn)

// Specific input fields
input(R.id.searchbox, "query")
input(R.id.tide_name, "Tide 1")
input(R.id.utm, "42, -72")

// Result/data views
hasText(R.id.result, "3.2808 ft")
hasText(R.id.total_percent_packed, "50% packed")

// Charts and special views
isVisible(R.id.chart)
scrollToEnd(R.id.scroll_view)

// Toolbar buttons
click(toolbarButton(R.id.paths_title, Side.Right))
```

### Andromeda List Item IDs

List items use Andromeda library IDs:

```kotlin
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

```kotlin
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

```kotlin
click(toolbarButton(R.id.title, Side.Right))
click(string(R.string.export))
```

### Quick Actions

```kotlin
private fun verifyQuickAction() {
    TestUtils.openQuickActions()
    click(quickAction(Tools.QUICK_ACTION_ID))
    // Verify action occurred
    TestUtils.closeQuickActions()
}
```

### Optional Elements

```kotlin
optional {
    hasText(string(R.string.disclaimer))
    clickOk()
}
```

### Navigate Back

```kotlin
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

```bash
./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`

