Skip to content

Comments

Token Migration UI Tests#2844

Merged
brandonpage merged 19 commits intoforcedotcom:devfrom
brandonpage:token-migration
Feb 24, 2026
Merged

Token Migration UI Tests#2844
brandonpage merged 19 commits intoforcedotcom:devfrom
brandonpage:token-migration

Conversation

@brandonpage
Copy link
Contributor

@brandonpage brandonpage commented Feb 23, 2026

This PR fundamentally changes the direction of our UI Test strategy for this repo:

  • The submodule and dependency on SalesforceSDK-UITests has been removed.
  • Most of the PageObject code uses Compose UI Test APIs which are extremely fast and appear to be very stable.
  • Espresso Web is used for most WebView interactions.
  • UIAutomator2 APIs are only used in the couple places that they are unfortunately necessary (explained in code comments).
  • The use of Android's Test Orchestrator also noticeably to helps stability with Firebase Test Lab at the cost of only ~10 seconds per test (now ~30s each).
  • Tests now utilize ui_test_config.json.

This PR is quite large, but contains no behavior changes to production code and only adds IDs to the existing UI.

Note: The UI Tests CI will fail on this PR because the code and yaml config (that does not change on PR) are out of sync. You can see my locally triggered Firebase Runs here, the first two failures were before Test Orchestrator.

…iometricAuthPolicy and handleDuplicateUserAccount. Split out TokenMigrationView and add tests.
…iew page objects by removing unnecessary calls. Fix tests on small and low API devices. Switch to sed to make install and set version scripts portable.
…ge into login and migration and increased timeouts for consistency.
@github-actions
Copy link

1 Warning
⚠️ Big PR, try to keep changes smaller if you can.

Generated by 🚫 Danger

Comment on lines +41 to +42
# sed -i.bak works identically on both BSD sed (macOS) and GNU sed (Linux)
sed -i.bak "s|__CONSUMER_KEY__|${MSDK_ANDROID_REMOTE_ACCESS_CONSUMER_KEY}|g" "$bootconfig" && rm -f "$bootconfig.bak"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@wmathurin gsed isn't installed on MacOS by default and doesn't exist on linux. This was the best I could come up with for a command that worked on both platforms but happy to hear suggestions.

}

@Serializable
data class UITestConfig(val loginHosts: List<LoginHost>, val apps: List<AppConfig>) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Again, Kotlin's Json and Serialization "plugins" are magic. Json.decodeFromString returns an instance of this data class.

* Handles the OAuth authorization "Allow" button that may appear
* after login or token migration.
*/
class AuthorizationPageObject(composeTestRule: ComposeTestRule) : BasePageObject(composeTestRule) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This class gave me the most trouble since I have to use UIAutomator2 to tap the "Allow" button (given it has no resource ID). I split it into separate login and migration functions so I could use Compose/Espresso to quickly check for signs of if we need to wait for and click the allow button or not. The slow waiting + quick short circuit in a loop seems to work well but I purposefully left log lines to make debugging easier if it ever fails/flaps.

Comment on lines +70 to +72
// Migrate within same CA (scope upgrade).
@Test
fun testMigrate_CA_AddMoreScopes() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Test comments, names and structure copied directly from iOS with few modifications.

Comment on lines +52 to +53
# sed -i.bak works identically on both BSD sed (macOS) and GNU sed (Linux)
sed -i.bak "s/version = \"[0-9\.]*\"/version = \"${versionName}\"/g" "${file}" && rm -f "${file}.bak"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@wmathurin I could revert this if you are uncomfortable with it. This script doesn't need to run on CI (at this time).

Copy link
Contributor

Choose a reason for hiding this comment

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

It's fine if it works the same.
And maybe one day, we will run the release from CI !

Copy link
Contributor

Choose a reason for hiding this comment

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

(Although we could just install gsed as part of the CI job).

Copy link
Contributor

Choose a reason for hiding this comment

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

gsed is being used across all the setversion.sh in all the repos - so maybe we keep it unchanged (for now).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

gsed does not exist for Linux, it's just sed. AFAIK GNU make gsed because BSD sed is a completely different implementation than UNIX. sed is not truly portable but it seems like the command I changed it to has the same result on both.

Copy link
Contributor

Choose a reason for hiding this comment

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

We should move to sed then. Maybe have a dedicated story and move all the setversion.sh across all the repos as part of that work?

@codecov
Copy link

codecov bot commented Feb 24, 2026

Codecov Report

❌ Patch coverage is 80.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 54.27%. Comparing base (9e8338d) to head (ae8fdd4).
⚠️ Report is 1 commits behind head on dev.

Files with missing lines Patch % Lines
...m/salesforce/androidsdk/ui/LoginOptionsActivity.kt 90.00% 0 Missing and 1 partial ⚠️
...m/salesforce/androidsdk/ui/components/LoginView.kt 0.00% 0 Missing and 1 partial ⚠️
...orce/androidsdk/ui/components/PickerBottomSheet.kt 75.00% 0 Missing and 1 partial ⚠️

❗ There is a different number of reports uploaded between BASE (9e8338d) and HEAD (ae8fdd4). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (9e8338d) HEAD (ae8fdd4)
SalesforceSDK 2 1
Additional details and impacted files
@@              Coverage Diff              @@
##                dev    #2844       +/-   ##
=============================================
- Coverage     64.55%   54.27%   -10.28%     
+ Complexity     2925     2423      -502     
=============================================
  Files           222      222               
  Lines         17323    17335       +12     
  Branches       2471     2473        +2     
=============================================
- Hits          11182     9409     -1773     
- Misses         4934     6843     +1909     
+ Partials       1207     1083      -124     
Components Coverage Δ
Analytics 47.92% <ø> (ø)
SalesforceSDK 39.84% <80.00%> (-19.19%) ⬇️
Hybrid 59.05% <ø> (ø)
SmartStore 78.20% <ø> (ø)
MobileSync 81.68% <ø> (ø)
React 52.36% <ø> (ø)
Files with missing lines Coverage Δ
...salesforce/androidsdk/ui/TokenMigrationActivity.kt 83.73% <ø> (ø)
...m/salesforce/androidsdk/ui/LoginOptionsActivity.kt 88.05% <90.00%> (+0.43%) ⬆️
...m/salesforce/androidsdk/ui/components/LoginView.kt 43.71% <0.00%> (-0.12%) ⬇️
...orce/androidsdk/ui/components/PickerBottomSheet.kt 76.02% <75.00%> (-0.02%) ⬇️

... and 59 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- name: Install Dependencies
env:
TEST_CREDENTIALS: ${{ secrets.TEST_CREDENTIALS }}
MSDK_ANDROID_REMOTE_ACCESS_CALLBACK_URL: ${{ secrets.MSDK_ANDROID_REMOTE_ACCESS_CALLBACK_URL }}
Copy link
Contributor

Choose a reason for hiding this comment

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

On iOS, I don't use/need those because the consumer key are always set through login options in the tests (and they come from ui_test_config.json).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah. It isn't possible (or at least reasonably worth the effort) to truly set the contents of the bootconfig file on Android so I don't have an equivalent "staticAppConfig". I wanted to have at least one test that uses the bootconfig file alone so I added it to CI.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh yeah, I remember that from the earlier PRs.
It's not ideal to have both platforms diverge on that (but I guess they were already quite different in their handling of bootconfig). It would be better if we could move away from any pre-build setup step. But like you said, it's probably too much work / we don't have enough time.

}

fun getTokens(): Tokens {
expandUserCredentialsSection()
Copy link
Contributor

Choose a reason for hiding this comment

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

On iOS, I ended up having export button that gives me back a JSON with all the values in the section - things were too slow when expanding and reading individual values one by one. But it looks like things are faster on Android?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Compose UI Test skips animations, syncs/synchronizes with Compose so you never have to sleep/wait and automatically scrolls (which was honestly a huge pain with UIAutomator2). I don't think it would really speed it up much but I will take a look.

Copy link
Contributor Author

@brandonpage brandonpage Feb 24, 2026

Choose a reason for hiding this comment

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

Shockingly they are about the same:

Screenshot 2026-02-23 at 8 35 46 PM

Edit: The above didn't account for some UI navigation overhead. The more accurate numbers are still close though, with the Json method being ~100ms faster on an API 36 device:
Screenshot 2026-02-24 at 8 21 58 AM

Unless the difference is larger on API 28 I'd rather just test using the UI since that also ensures its correctness.

Second Edit: ^ It's not. Between 100-200 ms difference.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm jealous, on iOS, things are really slow.

Copy link
Contributor

Choose a reason for hiding this comment

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

That gave me an idea - I'm now disabling animations on iOS (see wmathurin/SalesforceMobileSDK-iOS@7677881?w=1) - it's a bit faster but not as impressive as Android.


// endregion

private fun loginAndValidate(
Copy link
Contributor

Choose a reason for hiding this comment

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

This method will probably be useful in other login tests (not migration related) - so maybe it should move to a super class or helper class. On iOS, all the test suites derive from BaseAuthflowTester (and the test suites don't interact with the PageObject directly).

Comment on lines +52 to +53
# sed -i.bak works identically on both BSD sed (macOS) and GNU sed (Linux)
sed -i.bak "s/version = \"[0-9\.]*\"/version = \"${versionName}\"/g" "${file}" && rm -f "${file}.bak"
Copy link
Contributor

Choose a reason for hiding this comment

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

It's fine if it works the same.
And maybe one day, we will run the release from CI !

Comment on lines +52 to +53
# sed -i.bak works identically on both BSD sed (macOS) and GNU sed (Linux)
sed -i.bak "s/version = \"[0-9\.]*\"/version = \"${versionName}\"/g" "${file}" && rm -f "${file}.bak"
Copy link
Contributor

Choose a reason for hiding this comment

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

(Although we could just install gsed as part of the CI job).

Comment on lines +52 to +53
# sed -i.bak works identically on both BSD sed (macOS) and GNU sed (Linux)
sed -i.bak "s/version = \"[0-9\.]*\"/version = \"${versionName}\"/g" "${file}" && rm -f "${file}.bak"
Copy link
Contributor

Choose a reason for hiding this comment

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

gsed is being used across all the setversion.sh in all the repos - so maybe we keep it unchanged (for now).

@brandonpage brandonpage merged commit 6c1cbf3 into forcedotcom:dev Feb 24, 2026
4 of 7 checks passed
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.

2 participants