{"id":20244324,"url":"https://github.com/protonmail/android-fusion","last_synced_at":"2025-09-22T07:31:10.664Z","repository":{"id":230196753,"uuid":"739015134","full_name":"ProtonMail/android-fusion","owner":"ProtonMail","description":"Android Fusion is a extensible lightweight Android instrumented test framework that combines Espresso, UI Automator and Compose Ui Test into one easy-to-use API with the clear syntax, at the same time keeping the native Android frameworks APIs unchanged.","archived":false,"fork":false,"pushed_at":"2024-11-26T09:55:16.000Z","size":378,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":5,"default_branch":"release/0.9.99","last_synced_at":"2024-11-26T11:01:05.209Z","etag":null,"topics":["android","test-automation","testing-tools"],"latest_commit_sha":null,"homepage":"https://proton.me/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ProtonMail.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-04T15:20:35.000Z","updated_at":"2024-07-06T22:12:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"4c135e9d-38c3-4e6d-a11b-658db65b2a41","html_url":"https://github.com/ProtonMail/android-fusion","commit_stats":null,"previous_names":["protonmail/android-fusion"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProtonMail%2Fandroid-fusion","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProtonMail%2Fandroid-fusion/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProtonMail%2Fandroid-fusion/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProtonMail%2Fandroid-fusion/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ProtonMail","download_url":"https://codeload.github.com/ProtonMail/android-fusion/tar.gz/refs/heads/release/0.9.99","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233832503,"owners_count":18737210,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","test-automation","testing-tools"],"created_at":"2024-11-14T09:14:28.552Z","updated_at":"2025-09-22T07:31:05.291Z","avatar_url":"https://github.com/ProtonMail.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fusion\n\n**Fusion** is a extensible lightweight \nAndroid [instrumented](https://developer.android.com/training/testing/instrumented-tests)\n\ntest framework that combines\n**Espresso**, **UI Automator** and **ComposeUiTest** into one easy-to-use API with the clear syntax,\nat the same time keeping the native Android frameworks APIs unchanged.\n\n## Getting started\n\nAdd Fusion dependency to your build file:\n\n```kotlin\nrepositories {\n    mavenCentral()\n}\n\n// build.gradle\nandroidTestImplementation \"me.proton.test:fusion:0.9.97\"\n\n// build.gradle.kts\nandroidTestImplementation(\"me.proton.test:fusion:0.9.97\")\n```\n\nTo start using **Fusion API** simply import required builder\n\n### Espresso\n\n```kotlin\nimport me.proton.test.fusion.Fusion.view\nimport me.proton.test.fusion.Fusion.listView\nimport me.proton.test.fusion.Fusion.recyclerView\n\nclass EspressoTests {\n\n    @Test\n    fun onViewTest() {\n        view\n            .withId(R.id.text)\n            .withRootMatcher(isDialogPopup())\n            .typeText(\"Secure Email\")\n    }\n\n    @Test\n    fun onListViewTest() {\n        listView\n            .onListItem()\n            .atPosition(0)\n            .click()\n    }\n\n    @Test\n    fun onRecyclerViewTest() {\n        recyclerView\n            .withId(R.id.inbox)\n            .onItemAtPosition(0)\n            .click()\n\n        view\n            .withText(R.string.test)\n            .checkIsDisplayed()\n    }\n}\n```\n\nFull Fusion Espresso [documentation](./fusion/src/main/kotlin/me/proton/test/fusion/ui/espresso/README.md).\n\n\n### Compose UI\n\n  ```kotlin\nimport me.proton.test.fusion.Fusion.node\nimport me.proton.test.fusion.Fusion.allNodes\n\nclass ComposeUITests : FusionComposeTest {\n\n    @Test\n    fun singleNodeTest() {\n        node\n            .withTag(\"testTag\")\n            .click()\n\n        node\n            .withText(\"text\")\n            .assertExists()\n            .await {\n                assertIsDisplayed()\n            }\n    }\n\n    @Test\n    fun nodeCollectionTest() {\n        allNodes\n            .withTag(\"testTag\")\n            .assertEach(\n                node.containsText(\"test\")\n            )\n\n        allNodes\n            .withText(\"Item\")\n            .onFirst()\n            .click()\n            .await {\n                assertDoesNotExist()\n            }\n    }\n}\n```\n\nFull Fusion Compose [documentation](./fusion/src/main/kotlin/me/proton/test/fusion/ui/compose/README.md).\n\n### Device and UI Automator\n\n```kotlin\nimport me.proton.test.fusion.Fusion.device\nimport me.proton.test.fusion.Fusion.uiObject\nimport me.proton.test.fusion.Fusion.byObject\n\nclass InstrumentationTests {\n\n    @Test\n    fun deviceTest() {\n        device\n            .pressHome()\n            .pressRecentApps()\n    }\n\n    @Test\n    fun uiObjectTest() {\n        uiObject\n            .withPkg(\"me.package.example\")\n            .withText(\"Example\")\n            .click()\n    }\n\n    @Test\n    fun byObjectTest() {\n        byObject\n            .withContentDesc(\"Search\")\n            .click()\n\n        byObjects\n            .containsText(\"test\")\n            .atPosition(0)\n            .click()\n    }\n}\n```\n\nMore about Fusion capabilities for UIDevice device - [documentation](./fusion/src/main/kotlin/me/proton/test/fusion/ui/device/README.md).\n\nMore about Fusion for UIAutomator - [documentation](./fusion/src/main/kotlin/me/proton/test/fusion/ui/uiautomator/README.md).\n\n### Fusion API entry point\n\nThis is the entry point to [Fusion API](./fusion/src/main/kotlin/me/proton/test/fusion/Fusion.kt):\n\n- [Espresso](./fusion/src/main/kotlin/me/proton/test/fusion/ui/espresso/README.md):\n    - `intent` - use it to test intents. Covers `intending()` and `intended()` APIs.\n    - `listView` - should be used to interact with `ListView` elements. Covers Espresso `onData()`\n      API.\n    - `recyclerView` - should be used to interact with `RecyclerView` items or views inside\n      the `ViewHolder` item.\n    - `rootView` - use it to interact with root views.\n    - `view` - the shortcut to interact with `View` elements. Covers Espresso `onView()` API.\n- [UIAutomator](./fusion/src/main/kotlin/me/proton/test/fusion/ui/uiautomator/README.md):\n    - `uiObject` - an alias for `UiObject` UI Automator API.\n    - `byObject` - an alias for `UiObject2` UI Automator API.\n    - `byObjects` - an alias for `UiObject2` UI Automator API where you interact with\n      multiple `UiObject2` objects.\n- [ComposeUiTest](./fusion/src/main/kotlin/me/proton/test/fusion/ui/compose/README.md):\n    - `node` - an alias for `SemanticsNodeInteraction` ComposeUiTest API.\n    - `allNodes` - an alias for `SemanticsNodeInteractionCollection` ComposeUiTest API where you\n      interact with\n      multiple `SemanticsNodeInteraction` elements.\n- [Device](./fusion/src/main/kotlin/me/proton/test/fusion/ui/device/README.md):\n    - `device` - collection of functions to control the test device using the UiDevice API.\n\n### Fusion configuration\n\n[FusionConfig.kt](./fusion/src/main/kotlin/me/proton/test/fusion/FusionConfig.kt) file contains configuration parameters to control multiple Fusion parameters.\n\n#### Compose\n\n1. `useUnmergedTree` - controls whether the Compose UI Test framework should use an unmerged tree for UI tests. An unmerged tree could refer to a more detailed or raw view hierarchy, which might be useful for certain types of tests where the default merged or simplified view hierarchy isn't sufficient. Default is `false`.\n2. `testRule` - allows dynamically changing the test rule in a thread-safe manner during test execution.\n3. `shouldPrintHierarchyOnFailure` - instructs the testing framework to print or log the UI hierarchy in the event of a test failure. This can be invaluable for debugging, providing immediate insight into the UI state at the time of failure.\n\n#### UiAutomator\n\n1. **Search flags** - `shouldSearchByObjectEachAction` and `shouldSearchUiObjectEachAction` flags, both initialized to false, are used to control how UI elements (objects) are located, specifically in the context of using UI selectors or identifiers to interact with elements.\n\n    Both flags offer a way to balance between test robustness and execution speed. By default, with both flags set to false, the system assumes elements do not need to be re-located for each action, optimizing for speed.\n\n2. **Boost function** - `boost(idleTimeout: Long = 0L, selectorTimeout: Long = 0L, actionTimeout: Long = 50L)` is a utility designed specifically for enhancing the performance of UI tests automated with UI Automator in Android test automation projects. It aims to significantly reduce the execution time of UI tests by adjusting key timeouts in the UI Automator's Configurator.\n\n#### Timeout Management\nFusion offers a set of default timeouts for various operations within the test execution process. These include:\n\n- `waitTimeout`: Maximum time to wait for conditions to be met before proceeding.\n- `assertTimeout`: Time to wait before asserting a condition to ensure stability.\n- `watchInterval`: Frequency at which conditions or changes are checked.\n\nThese timeouts are encapsulated within AtomicReference objects to ensure thread-safe updates and retrievals, allowing dynamic adjustments during runtime.\n\n#### Execution Hooks\n\nDefines hooks for key moments in the test lifecycle, which can be customized per test needs. These hooks include:\n\n- `before`: Executed before each test case.\n- `after`: Executed after each test case.\n- `onFailure`: Invoked when a test case fails.\n- `onSuccess`: Invoked when a test case succeeds.\n\nThese hooks provide a flexible mechanism to integrate setup, teardown, and custom behavior based on test outcomes.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprotonmail%2Fandroid-fusion","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprotonmail%2Fandroid-fusion","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprotonmail%2Fandroid-fusion/lists"}