Skip to content

test: add end-to-end smoke tests covering every demo activity - #1007

Merged
dkhawk merged 10 commits into
mainfrom
test/demo-app-smoke-tests
Oct 1, 2026
Merged

dkhawk merged 10 commits into
mainfrom
test/demo-app-smoke-tests

Conversation

@kikoso

@kikoso kikoso commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Problem

Following up on a pull request currently means cloning it, building it, and clicking through every screen of the sample app to confirm nothing regressed. That is slow, easy to skip, and the coverage varies with whoever is reviewing.

What this adds

Two instrumentation tests in maps-app, both driven off allActivityGroups in Demo.kt, the single registry that already builds the on-screen demo list. A demo added to the app is covered automatically, with no change to either test. That is the property that makes this worth having rather than another list to keep in sync.

DemoAppSmokeTest

Parameterized over all 22 demos, two checks each:

  • demoLaunchesAndShowsMap: the activity reaches RESUMED, a MapView or StreetViewPanoramaView is attached, visible and non-zero sized, and nothing crashed on a background thread. The map surface is polled rather than checked once, because AndroidView lays it out a frame or more after the activity resumes.
  • demoSurvivesConfigurationChange: the same checks, then recreate(), then the same checks again. Configuration changes are where camera and marker state holders tend to regress and are tedious to verify by hand.

Map content is deliberately not asserted. Whether a particular marker or overlay is drawn belongs in the focused tests alongside this one; the value here is breadth.

DemoRegistryTest

Guards the registry itself. A demo is described in two places that have to agree: allActivityGroups and AndroidManifest.xml. Adding it to one and not the other compiles, builds, and only fails when someone taps the entry. Four checks: every demo resolves via PackageManager, is enabled, has non-blank title and description strings, and is not registered twice.

Verification

Run against a Pixel 8 emulator (API 36) with a valid Maps API key:

Suite Result
DemoAppSmokeTest 44 tests, 0 failures, 0 errors, 0 skipped, 138.6s
DemoRegistryTest 4 tests, 0 failures
:maps-app:lintDebug BUILD SUCCESSFUL, 0 issues

All 22 demos launch, show a map surface, and survive recreation today, so no demo needed an exemption and DEMOS_WITHOUT_MAP_SURFACE is empty.

Cost

DemoAppSmokeTest adds about 2.5 minutes to the emulator job, which currently runs 16 to 28 minutes. If that proves too much for the pull request gate, demoSurvivesConfigurationChange is the half to move to a nightly run: it roughly doubles the class's runtime and catches the rarer class of bug.

Notes

Both tests skip rather than fail when no Maps API key is configured, via assumeTrue(hasValidApiKey), matching how forks run CI without access to the secret. Worth knowing when reading a green run from a fork: the emulator job injects the key, so skipping only happens where the secret is genuinely unavailable.

@github-actions

Copy link
Copy Markdown

Coverage (unit tests)

No unit baseline recorded in coverage/history.csv yet, so this run only reports absolute numbers.

Module Line % Change Branch % Change
maps-compose 0.00% new 0.00% new
maps-compose-utils 2.04% new 0.49% new
maps-compose-widgets 0.00% new 0.00% new
TOTAL 0.42% new 0.09% new

Line and branch coverage from unit test reports. History is recorded in coverage/history.csv after each merge to main.

@kikoso
kikoso force-pushed the test/demo-app-smoke-tests branch from dd2684b to 5f8d892 Compare September 24, 2026 17:29
@kikoso
kikoso marked this pull request as ready for review September 24, 2026 17:29
@kikoso
kikoso requested a review from a team as a code owner October 1, 2026 11:07
@kikoso

kikoso commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Added three commits:

  • CI on API 36: emulators never update Google Play services, and older images bundle a version that crashes inside Play services when adding advanced markers (found in test: add end-to-end demo smoke test android-maps-utils#1805).
  • CI on Ubuntu with KVM: on macOS-latest-large the API 36 emulator took over five minutes to boot and the job hit its 30 minute timeout. Timeout raised to 45 minutes.
  • Zoom check: demoLaunchesAndShowsMap now zooms each map out and back in. With requireMapLoaded=true (passed by CI when ACTIONS_API_KEY is available) it also waits for tiles to render.

Locally on an API 34 emulator with a real key: DemoAppSmokeTest 44/44 pass with requireMapLoaded=true.

kikoso added 4 commits October 1, 2026 13:09
Reviewing a pull request currently means cloning it and clicking through
the sample app by hand to confirm nothing regressed. These two tests do
that walk automatically.

DemoAppSmokeTest is parameterized over allActivityGroups, the same
registry that builds the on-screen demo list, so a demo added to the app
is covered with no change to the test. Each demo is launched and checked
for three things: it reaches RESUMED, a MapView or StreetViewPanoramaView
is attached and laid out, and nothing crashes on a background thread. It
then recreates the activity and checks again, which is where camera and
marker state holders tend to regress.

DemoRegistryTest guards the registry itself. A demo is described both in
allActivityGroups and in AndroidManifest.xml; adding it to one and not
the other builds cleanly and only fails when someone taps the entry.

Map content is deliberately not asserted. Verifying that a particular
marker or overlay is drawn belongs in the focused tests alongside these;
the value here is breadth.
Emulators never update Google Play services. The bundled version on older
images crashes inside Play services when adding advanced markers. When the
Maps API key secret is available, the demo smoke test also waits for map
tiles to render.

(cherry picked from commit 22d2871)
… test

Zooming out and back in exercises the camera listeners the demos and the
library hook into. With requireMapLoaded=true, which CI passes when the
Maps API key secret is available, the test also waits for tiles to render.
On macOS-latest-large the API 36 emulator took over five minutes to boot
and the job hit its 30 minute timeout. Ubuntu runners support KVM and
boot it in about a minute. Raise the timeout to 45 minutes for headroom.
@kikoso
kikoso force-pushed the test/demo-app-smoke-tests branch from dafa07a to 12db67e Compare October 1, 2026 11:09
DemoMenuNavigationTest starts MainActivity, taps the demo's group and
entry, waits for its map, and presses back to the menu, so a broken menu
entry, click handler or back navigation is caught. DemoRegistryTest now
also fails when a demo activity is declared in the manifest but missing
from the menu. Adds test tags to the menu cards.
@kikoso

kikoso commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Added the menu flow:

  • DemoMenuNavigationTest (new): starts MainActivity, taps each demo's group and entry, waits for its map, and presses back to the menu, so a broken menu entry, click handler or back navigation is caught. DemoAppSmokeTest still launches each demo directly for the in-depth checks.
  • DemoRegistryTest.everyDeclaredActivityIsInTheMenu (new): the reverse of the manifest check, failing when a demo activity is declared but missing from the menu.
  • Test tags on the menu cards in Demo.kt, the only app change.

Locally on an API 34 emulator: DemoMenuNavigationTest 22/22 (about 1 minute), DemoRegistryTest 5/5.

@googlemaps-bot

googlemaps-bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Code Coverage

Overall Project 24.66% -0.08% ❌
Files changed 0% ❌

File Coverage
Demo.kt 0% -1.73% ❌

Move DemoAppSmokeTest, DemoMenuNavigationTest and DemoRegistryTest into a
smoke package. A new Demo smoke test workflow runs only that package on
API 36 with KVM and a real key, and the instrumentation workflow excludes
it and goes back to its previous runner, API level and timeout, so the
coverage history stays comparable. DemoAppSmokeTest now zooms a map that
is fully on screen, which fixes a flaky wait in MapsInLazyColumnActivity.
@kikoso

kikoso commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Split the smoke tests from the regular instrumentation tests:

  • DemoAppSmokeTest, DemoMenuNavigationTest and DemoRegistryTest moved to com.google.maps.android.compose.smoke.
  • New Demo smoke test workflow runs only that package on API 36 with KVM, a real key and requireMapLoaded=true. It skips with a notice when ACTIONS_API_KEY is not available.
  • Run instrumentation tests now excludes the package (notPackage) and is otherwise back to what it is on main (macOS, API 29, 30 minutes), so coverage history stays comparable.
  • Fixed a flaky wait: DemoAppSmokeTest now zooms a map that is fully on screen, which matters for MapsInLazyColumnActivity.

Locally: package=smoke runs 71/71 (44 + 22 + 5) with requireMapLoaded=true, and notPackage=smoke runs the 41 other tests, all passing.

@dkhawk dkhawk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with a few minor observations and suggestions:

  1. assumeValidApiKey in DemoMenuNavigationTest: The PR description notes that both suites skip when an API key is not present via assumeTrue(hasValidApiKey). DemoAppSmokeTest has this, but DemoMenuNavigationTest appears to be missing the @Before check (or assumeValidApiKey()). Adding it will prevent unexpected timeouts if someone runs the smoke suite locally without a key in secrets.properties.
  2. Defensive scroll on group headers: In DemoMenuNavigationTest, adding .performScrollTo() before .performClick() on groupTestTag(group) would protect against smaller screens or landscape orientation where lower groups might be below the fold.
  3. StreetView coverage in navigation: In DemoMenuNavigationTest, DEMOS_WITHOUT_MAP exempts StreetViewActivity because findMapView only looks for MapView. Since StreetViewPanoramaView supports getStreetViewPanoramaAsync, supporting both (like DemoAppSmokeTest does with mapSurfaces) would eliminate the exemption.
  4. Background crash detection: DemoAppSmokeTest's uncaught exception handler is great. Consider applying the same check to DemoMenuNavigationTest, and also checking assertNoUncaughtExceptions() in @After tearDown() to catch any crashes during activity teardown.

Overall, the design is excellent—generating the test matrices directly from allActivityGroups and keeping the manifest in sync via DemoRegistryTest makes this completely maintenance-free.

- DemoMenuNavigationTest scrolls the menu to each group and demo before
  clicking, since items below the fold are not composed until the
  LazyColumn scrolls to them.
- It covers StreetViewActivity through its StreetViewPanoramaView instead
  of exempting it. The wait advances the compose test clock, which drives
  every composition in the process: the panorama only appears after a
  recomposition that follows an async metadata request. Without a valid
  key, that demo is only checked for opening.
- Both tests record background-thread crashes and check for them in
  @after as well, to catch crashes during teardown. tearDown only
  restores the default handler it replaced.
@kikoso

kikoso commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks @dkhawk! Pushed c189955 with these:

  1. API key in DemoMenuNavigationTest: I didn't add assumeTrue here, for two reasons. Without a key the maps still become ready, so the menu test runs fine (I ran it locally with YOUR_API_KEY). And in this repo a failed assumption is reported as a failure, not a skip: without a key, all 44 DemoAppSmokeTest cases show up as failed with AssumptionViolatedException. That also affects the assumeValidApiKey() tests from test: skip map instrumentation tests when no Maps API key is available #1016, I think it's worth a follow-up. The one case that does need a key is StreetViewActivity (it waits for a Street View metadata request), so without a key that demo is only checked for opening. With the change, the menu test is 22/22 both with and without a key.
  2. Scroll before clicking: done, it now scrolls the LazyColumn to the group and then to the demo (performScrollToNode), since items below the fold are not composed until the list scrolls to them.
  3. StreetView: done, the exemption is gone and it waits for the StreetViewPanoramaView. This one was interesting: it timed out at first even with a key, because the compose rule drives the frame clock of every composition in the process, and the panorama only shows after a recomposition that follows the async request. The wait now advances mainClock.
  4. Background crashes: done, DemoMenuNavigationTest installs the same handler, and both tests also check in @After. I also made tearDown only restore the handler it replaced: when the key check skipped a test, it was restoring null.

Locally with a real key: 71/71 (44 + 22 + 5).

@kikoso

kikoso commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Correction on point 1: I mixed up the report with the build result. As #1016 notes, AGP records skipped assumptions as <failure> in the XML, but the build still passes, and keyless Dependabot runs have been green since. So no follow-up is needed for #1016. Not adding the assumeTrue here still makes sense, since the menu test doesn't need a key.

@dkhawk
dkhawk merged commit 29a87be into main Oct 1, 2026
13 checks passed
@dkhawk
dkhawk deleted the test/demo-app-smoke-tests branch October 1, 2026 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants