Add an End-to-End test suite for the Android SDK - #27
Open
brionmario wants to merge 3 commits into
Open
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This was referenced Sep 1, 2026
brionmario
force-pushed
the
mobile-e2e-tests
branch
from
September 1, 2026 12:42
227c1aa to
ee04651
Compare
Drive the Quickstart through real authentication against a real ThunderID server using Maestro: sign in and sign out, then register a new account and sign in as it. The suite lives in tests/e2e and one script, run-e2e.sh, owns the whole run, so CI executes exactly what a contributor runs locally. A PowerShell twin, run-e2e.ps1, covers contributors working on Windows. Maestro rather than Espresso because the sign-in and sign-up forms are rendered from the flow definition the server returns, not from static native views. The iOS and Flutter SDKs tag those fields identically, so one set of selectors works across all three platforms. Writing the suite surfaced three defects that affected users, not just tests: Compose keeps testTag inside its own semantics tree, so none of the flow fields were reachable from the platform accessibility tree. The components that render flow steps now opt their subtree in with testTagsAsResourceId. SignUp ignored FlowStatus.INCOMPLETE, which is what the server returns for every registration step, so the form never rendered at all and sign-up was unusable. SignIn already treated INCOMPLETE and PROMPT_ONLY alike. SignUp also tagged nothing, so it now tags its fields and actions the way SignIn does. The sample's sign-up sheet was never dismissed once the flow completed, leaving an empty sheet covering the app. Sign-in only appeared to work because a successful sign-in swaps the whole screen and tears the sheet down with it. Finally, restrict allowInsecureConnections to loopback hosts. It installed a trust-all manager and a permissive hostname verifier for any host, so an app that shipped with it enabled had no certificate validation on the channel carrying credentials, assertions and refresh tokens. It now applies only to localhost, 127.0.0.1, ::1 and 10.0.2.2, and raises a configuration error for anything else. Refs thunder-id/thunderid#5181 Signed-off-by: Brion <info@brionmario.com>
brionmario
force-pushed
the
mobile-e2e-tests
branch
from
September 1, 2026 15:09
ee04651 to
2b8a7c4
Compare
Every flow starts here, and a bare assertVisible gets Maestro's short default lookup timeout rather than the generous budget the rest of the suite uses. On a loaded CI emulator the landing screen does not always render inside it, which failed the Android sign-up flow 19 seconds in, before the flow had done anything. Wait for it explicitly instead. Signed-off-by: Brion <info@brionmario.com>
CI installed whatever Maestro was newest at the time, so the test runner changed under the suite between runs with nothing in the repository to show it: CI has been on 2.10.0 since it shipped while a contributor following the README gets whatever is current, which makes a CI-only failure impossible to reproduce faithfully. Pin it, and bump deliberately after checking the flows. The JUnit report gives a failed run a machine-readable result instead of a console log to scrape, and CI now collects it with the other debug artifacts. Signed-off-by: Brion <info@brionmario.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
The Android SDK had unit tests but no coverage that exercised it the way a person uses it. Unit tests stub the server out, so they cannot catch the failures that matter most to someone integrating the SDK: a flow step the SDK renders but cannot submit, a field the server renames, or an application whose configuration the SDK rejects at run time.
This adds a Maestro suite that drives the Quickstart sample against a real ThunderID server. It signs a user in, signs them out, registers a new account, and signs in as that new account.
Writing it surfaced four defects that affect users, not just tests. They are described under Approach.
Approach
Maestro rather than Espresso. The sign-in and sign-up forms are not static native views: the server returns a flow definition and the SDK renders it. All three mobile SDKs tag the resulting fields the same way,
thunderid-field-<identifier>andthunderid-action-<ref>, so one set of selectors and one set of flows works across iOS, Android and Flutter.One script owns the run.
tests/e2e/run-e2e.shstarts a server, provisions the test application and user, builds and installs the sample, and runs the flows. CI calls the same script through a composite action, so a green run locally and a green run in CI mean the same thing.run-e2e.ps1is the PowerShell twin for contributors on Windows, which is the one mobile SDK where Windows development is viable. Stages are skippable and every stage is idempotent.The test application is declarative.
thunderid-config.yamldefines atype: mobileapplication withattestation.devMode: true. A mobile application must normally prove its binary identity through Play Integrity before it can initiate a flow, which an emulator cannot satisfy.devModeis test only.Defects fixed
Compose test tags were invisible to anything outside Compose.
Modifier.testTaglives in Compose's own semantics tree, so none of the flow fields were reachable from the platform accessibility tree, and therefore not by UI Automator, Maestro, Appium, or any other black box driver. The components that render flow steps now opt their subtree in withtestTagsAsResourceId.Sign-up was completely broken.
SignUphandledFlowStatus.PROMPT_ONLYbut ignoredFlowStatus.INCOMPLETE, andINCOMPLETEis what the server returns for every registration step. The form was silently dropped and the sheet rendered empty, so a user tapping "Get started" saw a title and nothing else.SignInalready treated the two alike.SignUpalso tagged none of its fields or actions, unlikeSignIn, so it now does.The sample's sign-up sheet never closed. Nothing reset it when the flow completed, leaving an empty sheet covering the app. Sign-in only appeared unaffected because a successful sign-in swaps
RootViewtoHomeScreenand tears the sheet down as a side effect; sign-up does not establish a session, so the sheet stayed.allowInsecureConnectionsdisabled certificate validation for every host. It installed a trust-allX509TrustManagerand a hostname verifier returningtrueunconditionally, and nothing in the SDK gated it on a debuggable build. An app that shipped with it enabled had no certificate validation at all on the channel carrying credentials, assertions and refresh tokens, and it failed silently because the app kept working. It now applies only to loopback hosts (localhost,127.0.0.1,::1,10.0.2.2), where no network attacker can sit, and raises a configuration error for anything else. The development workflow is unchanged, which the suite demonstrates by running against10.0.2.2.Related Issues
Related PRs
Checklist
tests/e2e/README.md, plus the SDK Development section of the contributor docstests/e2e/flows/signin.yaml,tests/e2e/flows/signup.yamlbreaking changelabel added.Worth a reviewer's attention: narrowing
allowInsecureConnectionsto loopback is a behaviour change. Any caller relying on it for a non-loopback host now receives a configuration error instead of a silently insecure connection. That was the intent, but it is a change in observable behaviour.Security checks
The credentials in this PR (
e2e_mobile_user/TestPassword@123) belong to a throwaway account the suite creates on a local server. They are not secrets and grant nothing anywhere else.Verification
./gradlew ktlintCheck testDebugUnitTestpasses. The suite was run end to end against a freshly downloaded ThunderID v1.0.1 on an API 34 emulator, 2 of 2 flows passing, with the hardened certificate check in place.