package org.terst.nav import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith /** * Smoke tests: verify the main UI surfaces launch and respond correctly. * Run without GPS permission — LocationService is not started. * * Locally: ./gradlew connectedDebugAndroidTest * CI: smoke-test job via android-emulator-runner */ @RunWith(AndroidJUnit4::class) class MainActivitySmokeTest { @get:Rule val activityRule = ActivityScenarioRule(MainActivity::class.java) @Before fun setup() { NavApplication.isTesting = true } // ── Launch ───────────────────────────────────────────────────────────── @Test fun mainActivity_launches_withoutCrash() { activityRule.scenario.onActivity { activity -> assert(!activity.isFinishing) { "MainActivity finished immediately after launch" } } } // ── Bottom nav ───────────────────────────────────────────────────────── @Test fun bottomNav_allFourTabs_areDisplayed() { onView(withText("Map")).check(matches(isDisplayed())) onView(withText("Instruments")).check(matches(isDisplayed())) onView(withText("Log")).check(matches(isDisplayed())) onView(withText("Safety")).check(matches(isDisplayed())) } @Test fun bottomNav_safetyTab_showsSafetyDashboard() { onView(withText("Safety")).perform(click()) onView(withText("Safety Dashboard")).check(matches(isDisplayed())) onView(withText("ACTIVATE MOB")).check(matches(isDisplayed())) onView(withText("ANCHOR WATCH")).check(matches(isDisplayed())) } @Test fun bottomNav_logTab_showsVoiceLogUi() { onView(withText("Log")).perform(click()) onView(withContentDescription("Start voice recognition")).check(matches(isDisplayed())) } @Test fun bottomNav_instrumentsTab_isSelectable() { onView(withText("Instruments")).perform(click()) onView(withId(R.id.instrument_bottom_sheet)).check(matches(isDisplayed())) } @Test fun bottomNav_mapTab_returnsFromOverlay() { onView(withText("Safety")).perform(click()) onView(withText("Map")).perform(click()) onView(withId(R.id.mapView)).check(matches(isDisplayed())) } // ── Persistent FABs ──────────────────────────────────────────────────── @Test fun fabMob_isAlwaysVisible() { onView(withContentDescription("Man Overboard")).check(matches(isDisplayed())) } @Test fun fabMob_remainsVisibleOnSafetyTab() { onView(withText("Safety")).perform(click()) onView(withContentDescription("Man Overboard")).check(matches(isDisplayed())) } // ── Track recording ──────────────────────────────────────────────────── @Test fun fabRecordTrack_isDisplayedWithRecordDescription() { onView(withContentDescription("Record Track")).check(matches(isDisplayed())) } @Test fun fabRecordTrack_togglesToStopRecording_onFirstClick() { onView(withContentDescription("Record Track")).perform(click()) onView(withContentDescription("Stop Recording")).check(matches(isDisplayed())) } @Test fun fabRecordTrack_togglesBackToRecord_onSecondClick() { onView(withContentDescription("Record Track")).perform(click()) onView(withContentDescription("Stop Recording")).perform(click()) onView(withContentDescription("Record Track")).check(matches(isDisplayed())) } }